Largescale overhaul of the JEEPs interface to:
authorrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Thu, 20 Apr 2006 02:20:18 +0000 (02:20 +0000)
committerrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Thu, 20 Apr 2006 02:20:18 +0000 (02:20 +0000)
* Vastly widen device support
* Provide better independence of serial/usb.
* Provice better separation of USB protocol and physical layer.
* Provice better independence of the various OS layers.

29 files changed:
gpsbabel/jeeps/garminusb.h
gpsbabel/jeeps/gps.h
gpsbabel/jeeps/gpsapp.c
gpsbabel/jeeps/gpsapp.h
gpsbabel/jeeps/gpscom.c
gpsbabel/jeeps/gpscom.h
gpsbabel/jeeps/gpsdevice.c [new file with mode: 0644]
gpsbabel/jeeps/gpsdevice.h [new file with mode: 0644]
gpsbabel/jeeps/gpsdevice_ser.c [new file with mode: 0644]
gpsbabel/jeeps/gpsdevice_usb.c [new file with mode: 0644]
gpsbabel/jeeps/gpslibusb.c
gpsbabel/jeeps/gpsmem.c
gpsbabel/jeeps/gpsprot.c
gpsbabel/jeeps/gpsprot.h
gpsbabel/jeeps/gpsread.c
gpsbabel/jeeps/gpsread.h
gpsbabel/jeeps/gpsrqst.c
gpsbabel/jeeps/gpsrqst.h
gpsbabel/jeeps/gpssend.c
gpsbabel/jeeps/gpssend.h
gpsbabel/jeeps/gpsserial.c
gpsbabel/jeeps/gpsserial.h
gpsbabel/jeeps/gpsusbcommon.c
gpsbabel/jeeps/gpsusbint.h
gpsbabel/jeeps/gpsusbread.c
gpsbabel/jeeps/gpsusbsend.c
gpsbabel/jeeps/gpsusbstub.c
gpsbabel/jeeps/gpsusbwin.c
gpsbabel/jeeps/gpsutil.h

index 569c23749185ecea27f21916a0faf6d5a2ed9088..a05f9c15d059abcc5ca3b5209cb2f1432df08653 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Definitions for Garmin USB protocol and implementation.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -56,9 +56,8 @@ struct garmin_unit_info {
 
 int gusb_cmd_send(const garmin_usb_packet *obuf, size_t sz);
 int gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz);
-int gusb_open(const char *portname);
-int gusb_close(const char *portname);
-int gusb_init(const char *portname);
+int gusb_init(const char *portname, gpsdevh **dh);
+int gusb_close(gpsdevh *);
 
 /*
  * New packet types in USB.
index fa3af7ea0d7197f8def21e0749868879223f6a65..3a0c66e86220cab11cbbf961b9a03bb641ae2d3a 100644 (file)
@@ -86,9 +86,12 @@ typedef struct GPS_STrack
     time_t   Time;             /* Unix time */
     float    alt;              /* Altitude */
     float    dpth;             /* Depth    */
+    float    temperature;      /* Temperature.  Degrees Celsius. */
+    int      temperature_populated; /* True if above is valid. */
     int32    heartrate;                /* Heatrate as in Garmin 301 */
-    int32    tnew;             /* New track? */
-    int32    ishdr;            /* Track header? */
+    unsigned int   tnew:1;     /* New track? */
+    unsigned int   ishdr:1;    /* Track header? */
+    unsigned int   no_latlon:1;        /* True if no valid lat/lon found. */
     int32    dspl;             /* Display on map? */
     int32    colour;           /* Colour */
     char     trk_ident[256];   /* Track identifier */
@@ -152,8 +155,12 @@ typedef struct GPS_SWay
     char   rte_link_subclass[18];
     char   rte_link_ident[256];
 
-    char     Time_populated;   /* 1 if true */
-    time_t   Time;             /* Unix time */
+    char     time_populated;   /* 1 if true */
+    time_t   time;             /* Unix time */
+    char     temperature_populated;
+    float    temperature;              /* Degrees celsius. */
+    uint16   category;
+     
 } GPS_OWay, *GPS_PWay;
 
 /*
@@ -173,7 +180,7 @@ typedef struct GPS_SLap_Data {
 
 
 
-#include "gpsserial.h"
+#include "gpsdevice.h"
 #include "gpssend.h"
 #include "gpsread.h"
 #include "gpsutil.h"
index b815edcaed2155d3ed51a62ab0ac140dee63c203..967c95b835f22d96d4b386cada8972793eb32d68 100644 (file)
@@ -4,7 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
-** @modified 2004, 2005, 2006 Robert Lipe
+** @modified Copyright (C) 2004, 2005, 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
 ** Boston, MA  02111-1307, USA.
 ********************************************************************/
 #include "gps.h"
-#include "garminusb.h"
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <stdlib.h>
 #include <ctype.h>
 
+/*
+ * This violates the layering design, but is needed for device discovery.
+ * See the use of gps_is_usb and GPS_Packet_Read_usb below.
+ */
+#include "garminusb.h"
+#include "gpsusbint.h"
+
 #define XMIN(a,b) (a < b? a : b)
 
 static int32    GPS_A000(const char *port);
@@ -74,6 +80,8 @@ static void   GPS_D152_Send(UC *data, GPS_PWay way, int32 *len);
 static void   GPS_D154_Send(UC *data, GPS_PWay way, int32 *len);
 static void   GPS_D155_Send(UC *data, GPS_PWay way, int32 *len);
 
+static void   GPS_D120_Get(int n, char *data);
+
 static void   GPS_D200_Get(GPS_PWay *way, UC *s);
 static void   GPS_D201_Get(GPS_PWay *way, UC *s);
 static void   GPS_D202_Get(GPS_PWay *way, UC *s);
@@ -90,10 +98,10 @@ static void   GPS_D400_Send(UC *data, GPS_PWay way, int32 *len);
 static void   GPS_D403_Send(UC *data, GPS_PWay way, int32 *len);
 static void   GPS_D450_Send(UC *data, GPS_PWay way, int32 *len);
 
-static int32    GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32    GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32    GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32    GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
+static int32    GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32    GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32    GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32    GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
 static void   GPS_D500_Send(UC *data, GPS_PAlmanac alm);
 static void   GPS_D501_Send(UC *data, GPS_PAlmanac alm);
 static void   GPS_D550_Send(UC *data, GPS_PAlmanac alm);
@@ -148,17 +156,16 @@ int32 GPS_Init(const char *port)
     
     (void) GPS_Util_Little();    
 
-    /*
-     *  Decide here if the portname refers to a USB device and set the 
-     *  global that's used as in inflection point for other decisions later.
-     */
-    gps_is_usb = (0 == strncmp(port, "usb:", 4));
-
     ret = GPS_A000(port);
     if(ret<0) return ret;
-
     gps_save_time = GPS_Command_Get_Time(port);
-    if(!gps_save_time) {
+
+    /*
+     * Some units may be unable to return time, such as a C320 when in 
+     * charging mode.  Only consider it fatal if the unit returns an error,
+     * not just absence of returning a time.
+     */
+    if(gps_save_time < 0) {
        return FRAMING_ERROR;
     }
 
@@ -180,16 +187,16 @@ int32 GPS_Init(const char *port)
 ************************************************************************/
 static int32 GPS_A000(const char *port)
 {
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int16 version;
     int16 id;
 
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
-    if(!gps_is_usb && !GPS_Serial_Flush(fd))
+    if(!GPS_Device_Flush(fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -215,11 +222,17 @@ static int32 GPS_A000(const char *port)
     GPS_User("Unit:\t%s\nID:\t%d\nVersion:\t%.2f", 
        gps_save_string, gps_save_id, gps_save_version);
 
-
+#if 0
     gps_date_time_transfer = pA600;
     gps_date_time_type     = pD600;  /* All models so far */
     gps_position_transfer  = pA700;
     gps_position_type      = pD700;  /* All models so far */
+#else
+    gps_date_time_transfer = -1;
+    gps_date_time_type     = -1;
+    gps_position_transfer  = -1;
+    gps_position_type      = -1;
+#endif
     gps_pvt_transfer       = -1;
     gps_pvt_type           = -1;
     gps_prx_waypt_transfer = -1;
@@ -229,7 +242,7 @@ static int32 GPS_A000(const char *port)
     gps_trk_hdr_type       = -1;
     gps_rte_link_type      = -1;
     
-    if(!GPS_Serial_Wait(fd))
+    if(!GPS_Device_Wait(fd))
     {
        GPS_Warning("A001 protocol not supported");
        id = GPS_Protocol_Version_Change(id,version);
@@ -246,28 +259,47 @@ static int32 GPS_A000(const char *port)
         * reading until we incur a timeout.
         * Worse still, the serial layer assumes a read timeout is a
         * fatal error, while the USB layer (correctly) returns that error
-        * to the caller.  So we call GPS_Serial_Wait which spins into 
+        * to the caller.  So we call GPS_Device_Wait which spins into 
         * a delay/select for the serial system and a NOP for USB.
+        *
+        * Worse _yet_, this is the one place in all of Garmin Protocolsville
+        * where we don't know a priori how many packets will be sent in
+        * response.   Since we want the lower levels of the USB handler
+        * to handle the ugliness of the "return to interrupt" packets, we
+        * reach behind that automation here and hand that ourselves.
         */
        for (i = 0; i < 25; i++) {
            rec->type = 0;
-           
-           if(!GPS_Serial_Wait(fd))
-                   goto carry_on;
 
-           if (GPS_Packet_Read(fd, &rec) <= 0) {
-                   goto carry_on;
-           }
+           if (gps_is_usb) {
+               GPS_Packet_Read_usb(fd, &rec, 0);
+           } else {
+               if(!GPS_Device_Wait(fd))
+                       goto carry_on;
 
-           GPS_Send_Ack(fd, &tra, &rec);
+               if (GPS_Packet_Read(fd, &rec) <= 0) {
+                       goto carry_on;
+               }
+
+               GPS_Send_Ack(fd, &tra, &rec);
+           }
 
            if (rec->type == 0xfd) {
-                   GPS_A001(rec);
-/* XXX This is wrong.   Since we don't have a timeout on a read in Windows 
- * (!) and this phase of the protocol is one of the very rare ones where we
- * don't know how many packets to expect, we have a big problem here.
- */
-goto carry_on;
+               GPS_A001(rec);
+               goto carry_on;
+           }
+
+          /*
+           * If a 296 has previously been interrupted, it's going to
+           * ignore the session request (grrrr) and continue to send 
+           * us left over packets.   So if we see anything that isn't
+           * part of our A000 discovery  cycle, reset the counter and
+           * continue to loop.
+           *
+           * Garmin acknowledges this is a firmware defect.
+           */
+           if (rec->type < 0xf8) {
+               i = 0;
            }
        }
        fatal("Failed to find a product inquiry response.\n");
@@ -278,11 +310,10 @@ carry_on:
     if(gps_pvt_transfer != -1)
        GPS_A800_Off(port,&fd);
     
-
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -343,113 +374,50 @@ static void GPS_A001(GPS_PPacket packet)
        case 'A':
            GPS_User("\nCapability %c%d:", tag, data);
            lasta = data;
-           if(data<100)
-           {
-               if(data==10)
+           switch (data) {
+               case 10:
                    gps_device_command = pA010-10;
-               else if(data==11)
-                   gps_device_command = pA011-10;
-               else    
-                   GPS_Protocol_Error(tag,data);
-               continue;
-           }
-           else if(data<200)
-           {
-               if(data==100)
+                   break;
+               case 11:
+                   gps_device_command = pA010-10;
+                   break;
+               case 100:
                    gps_waypt_transfer = pA100;
-               /* Ignore A101 Waypoint Category Transfer Protocol. */
-               continue;
-           }
-           else if(data<300)
-           {
-               if(data==200)
+                   break;
+               case 101:
+                   gps_category_transfer = pA101;
+                   break;
+               case 200:
                    gps_route_transfer = pA200;
-               else if(data==201)
+                   break;
+               case 201:
                    gps_route_transfer = pA201;
-               else
-                   GPS_Protocol_Error(tag,data);               
-               continue;
-           }
-           else if(data<400)
-           {
-                   switch (data) {
-                   case 300: 
-                           gps_trk_transfer = pA300;
-                           break;
-                   case 301:
-                           gps_trk_transfer = pA301;
-                           break;
-                   case 302:
-                           gps_trk_transfer = pA302;
-                           break;
-                   default:
-                           GPS_Protocol_Error(tag,data);
-                   }
-               continue;
-           }
-           else if(data<500)
-           {
-               if(data!=400)
-                   GPS_Protocol_Error(tag,data);
-               else
+                   break;
+               case 300: 
+                   gps_trk_transfer = pA300;
+                   break;
+               case 301:
+                   gps_trk_transfer = pA301;
+                   break;
+               case 302:
+                   gps_trk_transfer = pA302;
+                   break;
+               case 400:
                    gps_prx_waypt_transfer = pA400;
-               continue;
-           }
-           else if(data<600)
-           {
-               if(data!=500)
-                   GPS_Protocol_Error(tag,data);
-               else
+                   break;
+               case 500:
                    gps_almanac_transfer = pA500;
-               continue;
-           }
-           else if(data<700)
-           {
-               if (data == 600)
+                   break;
+               case 600:
                    gps_date_time_transfer = pA600;
-               else {
-                   /* Stupid  undocumented 60C packets */
-                   /* GPS_Protocol_Error(tag,data); */
-                    continue;
-               }
-               continue;
-           }
-           else if(data<800)
-           {
-               if(data!=700)
-                   GPS_Protocol_Error(tag,data);
-               gps_position_transfer = pA700;
-               continue;
-           }
-           else if(data<900)
-           {
-               if (data == 800)
+                   break;
+               case 700:
+                   gps_position_transfer = pA700;
+                   break;
+               case 800:
                    gps_pvt_transfer = pA800;
-               /*
-                * Undocumented A802 packets introduced on Vista 3.60 f/w.
-                * else  
-                *  GPS_Protocol_Error(tag,data);
-                */
-               continue;
-           }
-           else if (data < 1000)
-           {
-                       /* Stupid Garmin undocumented "A900" packets
-                        * as returned by GPS76, Emap, III, and V in 
-                        * later firmware.
-                        */
-                   continue;
-           }
-           else if (data < 1100)
-           {
-                       /* Stupid Garmin undocumented "A100[2345]" packets
-                        * as returned by Forerunner 301.
-                        */
-                   continue;
-           }
-           else
-           {
-               GPS_Protocol_Error(tag,data);
+                   break;
+
            }
            break;
 
@@ -457,28 +425,50 @@ static void GPS_A001(GPS_PPacket packet)
            GPS_User(" %c%d", tag, data);
            if(lasta<200)
            {
-               if(data<=110 && data>=100)
-               {
-                   gps_waypt_type = data;
-                   continue;
-               }
-               if(data<153 && data>=150)
-               {
-                   gps_waypt_type = data;
-                   continue;
-               }
-               if(data<156 && data>=154)
-               {
-                   gps_waypt_type = data;
-                   continue;
-               }
-               if (data == 120) 
-               {
-                       /* Quest 3.0 has a D120  for Wpt category ignore it*/
-                       continue;
+               switch (data) {
+                       case 100:
+                       case 101:
+                       case 102:
+                       case 103:
+                       case 104:
+                       case 105:
+                       case 106:
+                       case 107:
+                       case 108:
+                       case 109:
+                       case 110:
+                       /* 15x is panel-mount aviation */
+                       case 150:
+                       case 151:
+                       case 152:
+                       /* 153 not documented */
+                       case 154:
+                       case 155:
+                               gps_waypt_type = data;
+                               break;
+
+                       /* 
+                        * Observered on Quest 3.0, 27xx, 27x, 29x.
+                        */
+                       case 120:
+                               gps_category_type = data;
+                               break;
+
+                       case 200:
+                       case 201:
+                       case 202:
+                               gps_rte_hdr_type = data;
+                               break;
+                       
+                       /* 210 Link packets appear in newer models, but the
+                        * doc isn't sufficiently clear on what they really
+                        * mean.
+                        */
+                       case 210:
+                               gps_rte_link_type = data;
+                               break;
+                       
                }
-               else
-                   GPS_Protocol_Error(tag,data);
            }
            
 
@@ -531,6 +521,7 @@ static void GPS_A001(GPS_PPacket packet)
                            case 301: gps_trk_type = pD301; break;
                            case 302: gps_trk_type = pD302; break;
                            case 303: gps_trk_type = pD303; break;
+                           case 304: gps_trk_type = pD304; break;
                            case 310: gps_trk_hdr_type = pD310; break;
                            case 311: gps_trk_hdr_type = pD311; break;
                            case 312: gps_trk_hdr_type = pD312; break;
@@ -651,14 +642,14 @@ static void GPS_A001(GPS_PPacket packet)
 int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
     int32 i;
 
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -698,10 +689,13 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
        if(!((*way)[i]=GPS_Way_New()))
            return MEMORY_ERROR;
 
-       if(!GPS_Packet_Read(fd, &rec))
+       if(!GPS_Packet_Read(fd, &rec)) {
            return gps_errno;
-       if(!GPS_Send_Ack(fd, &tra, &rec))
+       }
+
+       if(!GPS_Send_Ack(fd, &tra, &rec)) {
            return gps_errno;
+       }
 
        switch(gps_waypt_type)
        {
@@ -770,7 +764,7 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
 
     if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
     {
-       GPS_Error("A100_GET: Error transferring waypoints.  Expected %d completion code.  Got %d", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type);
+       GPS_Error("A100_GET: Error transferring waypoints.  Expected %d completion code.  Got %d.  %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n);
        return FRAMING_ERROR;
     }
 
@@ -783,7 +777,7 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return n;
@@ -806,13 +800,13 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
 int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *))
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
     int32 len;
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -919,13 +913,84 @@ int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
 }
 
 
+/*
+ * Get the list of waypoint categories from the receiver.
+ */
+int32 GPS_A101_Get(const char *port)
+{
+    static UC data[2];
+    gpsdevh *fd;
+    GPS_PPacket tra;
+    GPS_PPacket rec;
+    int32 n;
+    int32 i;
+
+
+    if(!GPS_Device_On(port,&fd))
+       return gps_errno;
+
+    if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
+       return MEMORY_ERROR;
+
+    GPS_Util_Put_Short(data,
+                      COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt_Cats);
+    GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data,
+                   data,2);
+
+    if(!GPS_Write_Packet(fd,tra))
+    {
+       GPS_Error("A101_Get: Cannot write packet");
+       return FRAMING_ERROR;
+    }
+    
+    if(!GPS_Get_Ack(fd, &tra, &rec))
+    {
+       GPS_Error("A101_Get: No acknowledge");  
+       return FRAMING_ERROR;
+    }
+
+    GPS_Packet_Read(fd, &rec);
+    GPS_Send_Ack(fd, &tra, &rec);
+
+    n = GPS_Util_Get_Short(rec->data);
+    for (i = 0; i < n; ++i) {
+        if(!GPS_Packet_Read(fd, &rec)) {
+            return gps_errno;
+        }
+        if(!GPS_Send_Ack(fd, &tra, &rec)) {
+            return gps_errno;
+        }
+       switch(gps_category_type) {
+       case pD120:
+           GPS_D120_Get(i,(char *) rec->data);
+           break;
+       }
+    }
+    if(!GPS_Packet_Read(fd, &rec))
+        return gps_errno;
+    if(!GPS_Send_Ack(fd, &tra, &rec))
+        return gps_errno;
+
+    if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
+    {
+        GPS_Error("A101_Get: Error transferring waypoints.  Expected %d completion code.  Got %d.  %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n);
+        return FRAMING_ERROR;
+    }
+
+
+    if(!GPS_Device_Off(fd))
+       return gps_errno;
+
+    return 1;
+
+}
 
 /* @funcstatic GPS_D100_Get *********************************************
 **
@@ -1325,7 +1390,7 @@ static void GPS_D109_Get(GPS_PWay *way, UC *s, int protoid)
 
     p=s;
 
-    (*way)->prot = 109;
+    (*way)->prot = protoid;
     (*way)->wpt_class = *p++;
     (*way)->colour    = *p++;
     (*way)->dspl      = *p++;
@@ -1352,9 +1417,26 @@ static void GPS_D109_Get(GPS_PWay *way, UC *s, int protoid)
 
     p += 4; /* Skip over "outbound link ete in seconds */
     if (protoid == 110) {
-       p += 4; /* skip float temp */
-       p += 4;  /* skip longword time */
-       p += 2; /* skip int "category membership " */
+       float gps_temp;
+       int gps_time;
+       gps_temp = GPS_Util_Get_Float(p);
+       p+=4;
+       if (gps_temp <= 1.0e24) {
+               (*way)->temperature_populated = 1;
+               (*way)->temperature = gps_temp;
+       }
+
+       gps_time = GPS_Util_Get_Uint(p);
+       p+=4;
+       /* The spec says that 0xffffffff is unknown, but the 60CSX with
+        * firmware 2.5.0 writes zero.
+        */
+       if (gps_time != 0xffffffff && gps_time != 0) {
+               (*way)->time_populated = 1;
+               (*way)->time = GPS_Math_Gtime_To_Utime(gps_time);
+       }
+       (*way)->category = GPS_Util_Get_Short(p);
+       p += 2;
     }
 
     q = (UC *) (*way)->ident;
@@ -1622,6 +1704,32 @@ static void GPS_D155_Get(GPS_PWay *way, UC *s)
     return;
 }
 
+/*
+ * We'll cheat for now.  We know there are no more than 16 categories
+ * as of this writing for no data type exposes more than 16 bits in the
+ * bitmask of categories.  
+ */
+static char categories[16][17];
+/* 
+ * Read descriptor s into category number N;
+ */
+static
+void GPS_D120_Get(int cat_num, char *s)
+{
+       /* we're guaranteed to have no more than 16 chars plus a 
+        * null terminator. 
+        * 
+        * If the unit returned no string, the user has not configured one,
+        * so mimic the behaviour of the 276/296.
+        */
+
+       if (*s) {
+               strncpy(categories[cat_num], s, sizeof (categories[0]));
+       } else {
+               snprintf(categories[cat_num], sizeof (categories[0]), 
+                       "Category %d", cat_num+1);
+       }
+}
 
 
 /* @funcstatic GPS_D100_Send *******************************************
@@ -2044,14 +2152,15 @@ static void GPS_D109_Send(UC *data, GPS_PWay way, int32 *len, int protoid)
        GPS_Util_Put_Float(p, temp);
        p += 4;
 
-       if (way->Time_populated) {
-               GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->Time));
+       if (way->time_populated) {
+               GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->time));
                p+=sizeof(uint32);
        } else {
                for(i=0;i<4;++i) *p++ = 0xff; /* unknown time*/
        }
 
-       for(i=0;i<2;++i) *p++ = 0x00; /* D110 category */
+       GPS_Util_Put_Short(p, (US) way->category);; /* D110 category */
+       p += 2;
     }
 
     q = (UC *) way->ident;
@@ -2334,14 +2443,14 @@ static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len)
 int32 GPS_A200_Get(const char *port, GPS_PWay **way)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
     int32 i;
 
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -2489,7 +2598,7 @@ int32 GPS_A200_Get(const char *port, GPS_PWay **way)
     GPS_Packet_Del(&rec);
 
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return n;
@@ -2509,14 +2618,14 @@ int32 GPS_A200_Get(const char *port, GPS_PWay **way)
 int32 GPS_A201_Get(const char *port, GPS_PWay **way)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
     int32 i;
 
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -2682,7 +2791,7 @@ int32 GPS_A201_Get(const char *port, GPS_PWay **way)
     GPS_Packet_Del(&rec);
 
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return n;
@@ -2703,14 +2812,14 @@ int32 GPS_A201_Get(const char *port, GPS_PWay **way)
 int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
     int32 len;
     UC  method;
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -2831,7 +2940,7 @@ int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -2852,14 +2961,14 @@ int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n)
 int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
     int32 len;
     UC  method;
 
-    if(!GPS_Serial_On(port,&fd))
+    if(!GPS_Device_On(port,&fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -3000,7 +3109,7 @@ int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -3232,7 +3341,7 @@ static void GPS_D210_Send(UC *data, GPS_PWay way, int32 *len)
 int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
@@ -3250,7 +3359,7 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
        return GPS_UNSUPPORTED;
     }
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -3281,7 +3390,6 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
     for(i=0;i<n;++i)
        if(!((*trk)[i]=GPS_Track_New()))
            return MEMORY_ERROR;
-    
 
     switch(gps_trk_type)
     {
@@ -3303,7 +3411,7 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return ret;
@@ -3324,7 +3432,7 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
 int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
@@ -3340,7 +3448,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
        return GPS_UNSUPPORTED;
     }
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -3372,14 +3480,12 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
        if(!((*trk)[i]=GPS_Track_New()))
            return MEMORY_ERROR;
     
-
     for(i=0;i<n;++i)
     {
        if(!GPS_Packet_Read(fd, &rec))
            return gps_errno;
        if(!GPS_Send_Ack(fd, &tra, &rec))
            return gps_errno;
-
        if(rec->type == LINK_ID[gps_link_type].Pid_Trk_Hdr)
        {
            switch(gps_trk_hdr_type)
@@ -3419,6 +3525,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
            GPS_D302b_Get(&((*trk)[i]),rec->data);
            break;
        case pD303:
+       case pD304:
            GPS_D303b_Get(&((*trk)[i]),rec->data);
            break;
        default:
@@ -3431,7 +3538,6 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
        return gps_errno;
     if(!GPS_Send_Ack(fd, &tra, &rec))
        return gps_errno;
-
     if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
     {
        GPS_Error("A301_Get: Error transferring tracks");
@@ -3447,7 +3553,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return n;
@@ -3470,7 +3576,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
 int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
@@ -3486,7 +3592,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n)
        return GPS_UNSUPPORTED;
     }
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -3543,7 +3649,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -3564,7 +3670,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n)
 int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
@@ -3581,7 +3687,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
        return GPS_UNSUPPORTED;
     }
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -3665,7 +3771,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -3683,7 +3789,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
 **
 ** @return [int32] number of entries read
 ************************************************************************/
-int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd)
+int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *fd)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -3795,7 +3901,7 @@ void GPS_D302b_Get(GPS_PTrack *trk, UC *data)
 {
     UC *p;
     uint32 t;
-    double temp;
+    double gps_temp;
     
     p=data;
     
@@ -3821,7 +3927,12 @@ void GPS_D302b_Get(GPS_PTrack *trk, UC *data)
     /* The only difference between 302 and 301 is the presence of temp
      * in the middle.   Nice planning, eh?
      */
-    temp = GPS_Util_Get_Float(p);
+    gps_temp = GPS_Util_Get_Float(p);
+    if (gps_temp <= 1.0e24) {
+           (*trk)->temperature_populated = 1;
+           (*trk)->temperature = gps_temp;
+    }
+
     p+=sizeof(float);
 
     (*trk)->tnew = *p;
@@ -3845,7 +3956,7 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data)
     uint32 t;
     uint32 raw_lat, raw_lon;
     int lat_undefined, lon_undefined;
-    
+int i;    
     p=data;
     
     /* Latitude and longitude are sometimes invalid (0x7fffffff or 
@@ -3869,10 +3980,19 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data)
        (*trk)->lon = GPS_Math_Semi_To_Deg(raw_lon);
     p+=sizeof(int32);
 
+    /*
+     * Let the caller decide if it wants to toss trackpionts with only
+     * hear and/or time data.
+     */
+    if (lat_undefined || lon_undefined) {
+       (*trk)->no_latlon = 1;
+    }
+
     if (lat_undefined != lon_undefined) 
        GPS_Warning("GPS_D303b_Get: assumption (lat_undefined == lon_undefined) violated");
 
     t = GPS_Util_Get_Uint(p);
+
     if(!t || t==0x7fffffff || t==0xffffffff)
        (*trk)->Time=0;
     else
@@ -3886,12 +4006,23 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data)
     p+=sizeof(float);
 
     /* Heartrate is reported as 0 if there is no signal from 
-     * a heartrate monitor.  A uint32 is a bit overkill, even 
-     * for me in my state of fitness. Perhaps this is actually 
-     * a char or uint16, leaving room for a trk_seg bool at the end? 
+     * a heartrate monitor.  
+     *  305 and 304 are identical until now. 
      */
-    (*trk)->heartrate = GPS_Util_Get_Uint(p);
-    p+=sizeof(uint32);
+    switch (gps_trk_type) {
+    case pD304:
+       p+=4; /* A float indicating number of meters travelled. */
+       (*trk)->heartrate = (*p++);
+       /* crank cadence, RPM, 0xff if invalid.  */
+       p++;
+       /* sensor present.  Boolean */
+       p++;
+       
+       break;
+    case pD303:
+       (*trk)->heartrate = *p++;
+       break;
+    }
        
     /* There doesn't seem to be a trk_seg bool, or at least I've not 
      * observed it yet.  One possibility is to start a new segment 
@@ -3948,6 +4079,7 @@ void GPS_D311_Get(GPS_PTrack *trk, UC *s)
     /* Forerunner */
     identifier = GPS_Util_Get_Short(s);
     sprintf((*trk)->trk_ident, "%d", identifier);
+    (*trk)->tnew = 1;
 
     return;
 }
@@ -4111,7 +4243,7 @@ static void GPS_A300_Encode(UC *s, GPS_PTrack trk)
 int32 GPS_A400_Get(const char *port, GPS_PWay **way)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
@@ -4121,7 +4253,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way)
        return GPS_UNSUPPORTED;
 
 
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -4137,13 +4269,13 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way)
     if(!GPS_Get_Ack(fd, &tra, &rec))
        return gps_errno;
 
-    if(!GPS_Serial_Chars_Ready(fd))
+    if(!GPS_Device_Chars_Ready(fd))
     {
        GPS_Warning("A400 (ppx) protocol not supported");
        GPS_Packet_Del(&rec);
        GPS_Packet_Del(&tra);
 
-       if(!GPS_Serial_Off(port, fd))
+       if(!GPS_Device_Off(fd))
            return gps_errno;
 
        return GPS_UNSUPPORTED;
@@ -4253,7 +4385,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return n;
@@ -4274,7 +4406,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way)
 int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
@@ -4283,7 +4415,7 @@ int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n)
     if(gps_prx_waypt_transfer == -1)
        return GPS_UNSUPPORTED;
 
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -4380,7 +4512,7 @@ int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -4637,14 +4769,14 @@ static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len)
 int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 n;
     int32 i;
     int32 ret;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -4708,7 +4840,7 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return ret;
@@ -4731,7 +4863,7 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm)
 int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
 {
     UC data[GPS_ARB_LEN];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 i;
@@ -4740,7 +4872,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
     int32 posnsent;
     int32 ret;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -4829,7 +4961,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
      *  the time. Note that the time sent is held in gps_save_time
      *  global
      */
-    if(GPS_Serial_Wait(fd))
+    if(GPS_Device_Wait(fd))
     {
        if(!GPS_Packet_Read(fd, &rec))
            return gps_errno;
@@ -4855,7 +4987,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
      *  the position. Note that the posn sent is held in gps_save_lat
      *  and gps_save_lon global!
      */
-    if(GPS_Serial_Wait(fd))
+    if(GPS_Device_Wait(fd))
     {
        if(!GPS_Packet_Read(fd, &rec))
            return gps_errno;
@@ -4891,7 +5023,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -4909,7 +5041,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
 **
 ** @return [int32] number of entries read
 ************************************************************************/
-static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -4961,7 +5093,7 @@ static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
 **
 ** @return [int32] number of entries read
 ************************************************************************/
-static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -5013,7 +5145,7 @@ static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
 **
 ** @return [int32] number of entries read
 ************************************************************************/
-static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -5064,7 +5196,7 @@ static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
 **
 ** @return [int32] number of entries read
 ************************************************************************/
-static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -5309,12 +5441,12 @@ static void GPS_A500_Encode(UC *s, GPS_PAlmanac alm)
 time_t GPS_A600_Get(const char *port)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     time_t ret;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -5347,7 +5479,7 @@ time_t GPS_A600_Get(const char *port)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return ret;
@@ -5368,13 +5500,13 @@ time_t GPS_A600_Get(const char *port)
 ************************************************************************/
 int32 GPS_A600_Send(const char *port, time_t Time)
 {
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     int32 posnsent=0;
     int32 ret=0;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -5401,7 +5533,7 @@ int32 GPS_A600_Send(const char *port, time_t Time)
      *  the position. Note that the posn sent is held in gps_save_lat
      *  and gps_save_lon globals!
      */
-    if(GPS_Serial_Wait(fd))
+    if(GPS_Device_Wait(fd))
     {
        if(!GPS_Packet_Read(fd, &rec))
            return gps_errno;
@@ -5431,7 +5563,7 @@ int32 GPS_A600_Send(const char *port, time_t Time)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -5520,11 +5652,11 @@ void GPS_D600_Send(GPS_PPacket *packet, time_t Time)
 int32 GPS_A700_Get(const char *port, double *lat, double *lon)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -5558,7 +5690,7 @@ int32 GPS_A700_Get(const char *port, double *lat, double *lon)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -5578,11 +5710,11 @@ int32 GPS_A700_Get(const char *port, double *lat, double *lon)
 ************************************************************************/
 int32 GPS_A700_Send(const char *port, double lat, double lon)
 {
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
     
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -5608,7 +5740,7 @@ int32 GPS_A700_Send(const char *port, double lat, double lon)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -5687,13 +5819,13 @@ void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon)
 **
 ** @return [int32] success
 ************************************************************************/
-int32 GPS_A800_On(const char *port, int32 *fd)
+int32 GPS_A800_On(const char *port, gpsdevh **fd)
 {
     static UC data[2];
     GPS_PPacket tra;
     GPS_PPacket rec;
     
-    if(!GPS_Serial_On(port, fd))
+    if(!GPS_Device_On(port, fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -5729,7 +5861,7 @@ int32 GPS_A800_On(const char *port, int32 *fd)
 **
 ** @return [int32] success
 ************************************************************************/
-int32 GPS_A800_Off(const char *port, int32 *fd)
+int32 GPS_A800_Off(const char *port, gpsdevh **fd)
 {
     static UC data[2];
     GPS_PPacket tra;
@@ -5755,8 +5887,8 @@ int32 GPS_A800_Off(const char *port, int32 *fd)
     GPS_Packet_Del(&rec);
     GPS_Packet_Del(&tra);
 
-    if(!GPS_Serial_Off(port, *fd))
-       return gps_errno;
+//    if(!GPS_Device_Off(*fd))
+//     return gps_errno;
 
     return 1;
 }
@@ -5771,7 +5903,7 @@ int32 GPS_A800_Off(const char *port, int32 *fd)
 **
 ** @return [int32] success
 ************************************************************************/
-int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet)
+int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -5878,7 +6010,7 @@ void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt)
 int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket lappkt;
     GPS_PPacket recpkt;
     int32 i, n;
@@ -5886,7 +6018,7 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap)
     if (gps_lap_transfer == -1)
        return GPS_UNSUPPORTED;
 
-    if (!GPS_Serial_On(port, &fd))
+    if (!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if (!(lappkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New()))
@@ -5934,7 +6066,7 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap)
     GPS_Packet_Del(&lap);
     GPS_Packet_Del(&rec);
 
-    if (!GPS_Serial_Off(port, fd))
+    if (!GPS_Device_Off(fd))
        return gps_errno;
 
     return ret;
@@ -6012,6 +6144,7 @@ Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo)
                        case 50: *xinfo = "Xfer PVT Stop"; break;
                        case 92: *xinfo = "Flight Records"; break;
                        case 117: *xinfo = "Xfer Laps"; break;
+                       case 121: *xinfo = "Xfer Categories"; break;
                        default: *xinfo = "Unknown";
                }
                return "CMDDAT";
@@ -6056,5 +6189,7 @@ Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo)
                return "SESREQ";
        if (p == GUSB_SESSION_ACK)
                return "SESACK";
+       if (p == 152)
+               return "WPTCAT";
        return "UNKNOWN";
 }
index a8f6ffb131cb2bc6d9cb5ddb456a69e7ae93ea88..38a628f32aa8521b8fef2c9b95006fef9c991b53 100644 (file)
@@ -12,6 +12,7 @@ extern "C"
 int32  GPS_Init(const char *port);
 
 int32  GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int ct, GPS_PWay *));
+int32 GPS_A101_Get(const char *port);
 int32  GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *));
 
 int32  GPS_A200_Get(const char *port, GPS_PWay **way);
@@ -24,7 +25,7 @@ int32  GPS_A301_Get(const char *port, GPS_PTrack **trk);
 int32  GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n);
 int32  GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n);
 
-int32  GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd);
+int32  GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *h);
 void   GPS_D300b_Get(GPS_PTrack *trk, UC *data);
 void   GPS_D301b_Get(GPS_PTrack *trk, UC *data);
 void   GPS_D302b_Get(GPS_PTrack *trk, UC *data);
@@ -51,9 +52,9 @@ int32  GPS_A700_Send(const char *port, double lat, double lon);
 void   GPS_D700_Get(GPS_PPacket packet, double *lat, double *lon);
 void   GPS_D700_Send(GPS_PPacket *packet, double lat, double lon);
 
-int32  GPS_A800_On(const char *port, int32 *fd);
-int32  GPS_A800_Off(const char *port, int32 *fd);
-int32  GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet);
+int32  GPS_A800_On(const char *port, gpsdevh **fd);
+int32  GPS_A800_Off(const char *port, gpsdevh **fd);
+int32  GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet);
 void   GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt);
 
 const char * Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo);
index b3d6b3e05660818eba588b064a0d9328c8970703..e8a2874e1048da846ad7b2304cb9b6749282f889 100644 (file)
@@ -4,6 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2005, 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
 int32 GPS_Command_Off(const char *port)
 {
     static UC data[2];
-    int32 fd;
+    gpsdevh *fd;
     GPS_PPacket tra;
     GPS_PPacket rec;
 
     GPS_Util_Little();
 
-    gps_is_usb = (0 == strncmp(port, "usb:", 4));
-
-    if(!GPS_Serial_On(port, &fd))
+    if(!GPS_Device_On(port, &fd))
        return gps_errno;
 
     if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
@@ -57,7 +56,7 @@ int32 GPS_Command_Off(const char *port)
     if(!GPS_Write_Packet(fd,tra))
        return gps_errno;
 
-    if(!GPS_Serial_Chars_Ready(fd))
+    if(!GPS_Device_Chars_Ready(fd))
     {
        if(!GPS_Get_Ack(fd, &tra, &rec))
            return gps_errno;
@@ -67,7 +66,7 @@ int32 GPS_Command_Off(const char *port)
     GPS_Packet_Del(&tra);
     GPS_Packet_Del(&rec);
 
-    if(!GPS_Serial_Off(port, fd))
+    if(!GPS_Device_Off(fd))
        return gps_errno;
 
     return 1;
@@ -88,6 +87,19 @@ int32 GPS_Command_Get_Waypoint(const char *port, GPS_PWay **way, int (*cb)(int,
 {
     int32 ret=0;
 
+    /* 
+     * It's a bit tacky to do this up front without ticking the
+     * progress meter, but this come in pretty quickly...
+     */
+    if (gps_category_transfer) {
+       ret = GPS_A101_Get(port);
+       if (!ret) {
+fatal("blah");
+          return PROTOCOL_ERROR;
+       }
+       
+    }
+
     switch(gps_waypt_transfer)
     {
     case pA100:
@@ -224,7 +236,7 @@ int32 GPS_Command_Get_Track(const char *port, GPS_PTrack **trk)
        ret = GPS_A301_Get(port,trk);
        break;
     default:
-       GPS_Error("Get_Track: Unknown track protocol\n");
+       GPS_Error("Get_Track: Unknown track protocol %d\n", gps_trk_transfer);
        return PROTOCOL_ERROR;
     }
 
@@ -412,6 +424,12 @@ time_t GPS_Command_Get_Time(const char *port)
     case pA600:
        ret = GPS_A600_Get(port);
        break;
+    /* 
+     * If the unit doesn't support it (i.e. a C320 in charging mode), 
+     * but don't treat as error; return as zero.
+     */
+    case -1:
+       return 0;
     default:
        GPS_Error("Get_Time: Unknown date/time protocol");
        return PROTOCOL_ERROR;
@@ -472,6 +490,13 @@ int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon)
     case pA700:
        ret = GPS_A700_Get(port,lat,lon);
        break;
+    /* 
+     * If the unit doesn't support it (i.e. a C320 in charging mode), 
+     *  zero lat/lon, but don't treat as error. 
+     */
+    case -1:
+       *lat = *lon = 0.0;
+       break;
     default:
        GPS_Error("Get_Position: Unknown position protocol");
        return PROTOCOL_ERROR;
@@ -521,7 +546,7 @@ int32 GPS_Command_Send_Position(const char *port, double lat, double lon)
 ** @return [int32] success if supported and GPS starts sending
 ************************************************************************/
 
-int32 GPS_Command_Pvt_On(const char *port, int32 *fd)
+int32 GPS_Command_Pvt_On(const char *port, gpsdevh **fd)
 {
     int32 ret=0;
 
@@ -556,7 +581,7 @@ int32 GPS_Command_Pvt_On(const char *port, int32 *fd)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Command_Pvt_Off(const char *port, int32 *fd)
+int32 GPS_Command_Pvt_Off(const char *port, gpsdevh **fd)
 {
     int32 ret=0;
 
@@ -589,7 +614,7 @@ int32 GPS_Command_Pvt_Off(const char *port, int32 *fd)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt)
+int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt)
 {
     int32 ret=0;
 
index e8bbe1d2a8296fa0c216a3267088cc5e98e4696c..40f49c21987f5729f5266a6c9614eaf7ae7bd5f5 100644 (file)
@@ -18,9 +18,9 @@ int32  GPS_Command_Send_Time(const char *port, time_t Time);
 int32  GPS_Command_Get_Position(const char *port, double *lat, double *lon);
 int32  GPS_Command_Send_Position(const char *port, double lat, double lon);
 
-int32  GPS_Command_Pvt_On(const char *port, int32 *fd);
-int32  GPS_Command_Pvt_Off(const char *port, int32 *fd);
-int32  GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt);
+int32  GPS_Command_Pvt_On(const char *port, gpsdevh **fd);
+int32  GPS_Command_Pvt_Off(const char *port, gpsdevh **fd);
+int32  GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt);
 
 int32  GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm);
 int32  GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n);
diff --git a/gpsbabel/jeeps/gpsdevice.c b/gpsbabel/jeeps/gpsdevice.c
new file mode 100644 (file)
index 0000000..90c841f
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    Abstraction of underlying device types, serial or USB.  OS agnostic..
+
+    Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+    This program is free software{} you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation{} either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY{} without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program{} if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gps.h"
+#include "gpsdevice.h"
+#include "gpsserial.h"
+
+extern gps_device_ops gps_serial_ops;
+extern gps_device_ops gps_usb_ops;
+gps_device_ops *ops = NULL;
+
+int32  GPS_Device_On(const char *port, gpsdevh **fd)
+{
+       gps_is_usb = (0 == case_ignore_strncmp(port, "usb:", 4));
+
+       if (gps_is_usb) {
+               ops = &gps_usb_ops;
+       } else {
+               ops = &gps_serial_ops;
+       }
+
+       return (ops->Device_On)(port, fd);
+}
+
+int32  GPS_Device_Off(gpsdevh * fd)
+{
+       return (ops->Device_Off)(fd);
+}
+
+int32  GPS_Device_Wait(gpsdevh * fd)
+{
+       return (ops->Device_Wait)(fd);
+}
+
+int32  GPS_Device_Chars_Ready(gpsdevh * fd)
+{
+       return (ops->Device_Chars_Ready)(fd);
+}
+
+int32  GPS_Device_Flush(gpsdevh * fd)
+{
+       return (ops->Device_Flush)(fd);
+}
+
+int32  GPS_Write_Packet(gpsdevh * fd, GPS_PPacket packet)
+{
+       return (ops->Write_Packet)(fd, packet);
+}
+
+int32 GPS_Packet_Read(gpsdevh * fd, GPS_PPacket *packet)
+{
+       return (ops->Read_Packet)(fd, packet);
+}
+
+int32 GPS_Send_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec)
+{
+       return (ops->Send_Ack)(fd, tra, rec);
+}
+
+int32 GPS_Get_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec)
+{
+       return (ops->Get_Ack)(fd, tra, rec);
+}
+
+void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
+{
+       (ops->Make_Packet)(packet, type, data, n);
+}
diff --git a/gpsbabel/jeeps/gpsdevice.h b/gpsbabel/jeeps/gpsdevice.h
new file mode 100644 (file)
index 0000000..eb5d53d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+    Abstraction of underlying device types.
+
+    Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef gpsdevice_h
+#define gpsdevice_h
+
+typedef struct gpsdevh gpsdevh;
+
+#include "gps.h"
+
+#define usecDELAY 180000       /* Microseconds before GPS sends A001 */
+
+
+int32  GPS_Device_Chars_Ready(gpsdevh *fd);
+int32  GPS_Device_On(const char *port, gpsdevh **fd);
+int32  GPS_Device_Off(gpsdevh *fd);
+int32  GPS_Device_Wait(gpsdevh * fd);
+int32  GPS_Device_Flush(gpsdevh * fd);
+int32  GPS_Device_Read(int32 ignored, void *ibuf, int size);
+int32  GPS_Device_Write(int32 ignored, const void *obuf, int size);
+void   GPS_Device_Error(char *hdr, ...);
+int32  GPS_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32  GPS_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+int32  GPS_Packet_Read(gpsdevh *fd, GPS_PPacket *packet);
+int32  GPS_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+
+typedef int32 (*gps_device_op)(gpsdevh *);
+typedef int32 (*gps_device_op5)(const char *, gpsdevh **fd);
+typedef int32 (*gps_device_op10)(gpsdevh * fd,  GPS_PPacket *tra, GPS_PPacket *rec);
+typedef int32 (*gps_device_op12)(gpsdevh * fd, GPS_PPacket packet);
+typedef int32 (*gps_device_op13)(gpsdevh * fd, GPS_PPacket *packet);
+typedef void (*gps_device_op14)(GPS_PPacket *packet, UC type, UC *data, int16 n);
+typedef struct {
+       gps_device_op5 Device_On;
+       gps_device_op Device_Off;
+       gps_device_op Device_Chars_Ready;
+       gps_device_op Device_Wait;
+       gps_device_op Device_Flush;
+       gps_device_op10 Send_Ack;
+       gps_device_op10 Get_Ack;
+       gps_device_op13 Read_Packet;
+       gps_device_op14 Make_Packet;
+       gps_device_op12 Write_Packet;
+} gps_device_ops;
+
+#endif /* gpsdevice.h */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gpsbabel/jeeps/gpsdevice_ser.c b/gpsbabel/jeeps/gpsdevice_ser.c
new file mode 100644 (file)
index 0000000..29ff476
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    Serial operations.
+
+    Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gpsdevice.h"
+#include "gpsserial.h"
+#include "gpsread.h"
+
+gps_device_ops  gps_serial_ops = {
+       GPS_Serial_On,
+       GPS_Serial_Off,
+       GPS_Serial_Chars_Ready,
+       GPS_Serial_Wait,
+       GPS_Serial_Flush,
+       GPS_Serial_Send_Ack,
+       GPS_Serial_Get_Ack,
+       GPS_Serial_Packet_Read,
+       GPS_Serial_Make_Packet,
+       GPS_Serial_Write_Packet,
+};
diff --git a/gpsbabel/jeeps/gpsdevice_usb.c b/gpsbabel/jeeps/gpsdevice_usb.c
new file mode 100644 (file)
index 0000000..dd578c8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+    USB operations.
+
+    Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gpsdevice.h"
+#include "garminusb.h"
+#include "gpsusbint.h"
+#include "gpsusbcommon.h"
+
+static int32 success_stub(void)
+{
+       return 1;
+}
+
+static int32 gdu_on(const char *port, gpsdevh **fd)
+{
+       return gusb_init(port, fd);
+}
+
+static int32 gdu_off(gpsdevh *dh)
+{
+       return gusb_close(dh);
+}
+
+static int32  gdu_read(gpsdevh *fd, GPS_PPacket *packet)
+{
+       /* Default is to eat bulk request packets. */
+       return GPS_Packet_Read_usb(fd, packet, 1);
+}
+
+gps_device_ops gps_usb_ops = {
+       gdu_on,
+       gdu_off,
+       (gps_device_op) success_stub,
+       (gps_device_op) success_stub,
+       (gps_device_op) success_stub,
+       (gps_device_op10) success_stub,
+       (gps_device_op10) success_stub,
+       gdu_read,
+       GPS_Make_Packet_usb,
+       GPS_Write_Packet_usb
+};
index 0151720b90bb2fa9b799e1631b23a54d123efa2f..b0c25669b87bbeb89d66d443257f706a2770e3c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Physical/OS USB layer to talk to libusb.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -26,7 +26,9 @@
 #if HAVE_LIBUSB
 #include <usb.h>
 #include "gps.h"
+#include "gpslibusb.h"
 #include "garminusb.h"
+#include "gpsusbcommon.h"
 
 #define GARMIN_VID 0x91e
 
  * coalescion into packets anyway becuase of their serial background) will
  * compensate.
  */
-#define TMOUT_I 0100 /*  Milliseconds to timeout intr pipe access. */
+#define TMOUT_I 3000 /*  Milliseconds to timeout intr pipe access. */
+#define TMOUT_B 3000 /*  Milliseconds to timeout bulk pipe access. */
 
-int gusb_intr_in_ep;
-int gusb_bulk_out_ep;
-int gusb_bulk_in_ep;
 
-static const char  oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0};
-garmin_usb_packet iresp;
-
-static struct usb_bus *busses;
-static usb_dev_handle *udev;
-static void garmin_usb_scan(void);
-static void garmin_usb_syncup(void);
-
-int
-gusb_init(const char *portname)
-{
-// usb_set_debug(99);
-       usb_init();
-       usb_find_busses();
-       usb_find_devices();
-       busses = usb_get_busses();
-       garmin_usb_scan();
-
-       return 1;
-}
+/* 
+ * TODO: this should all be moved into libusbdata in gpslibusb.h,
+ * allocated once here in gusb_start, and deallocated at the end.
+ */
+static int gusb_intr_in_ep;
+static int gusb_bulk_out_ep;
+static int gusb_bulk_in_ep;
 
-static void dump(char *msg, const unsigned char *in, int r)
-{
-       int i;
-       printf("%s: %d\n", msg, r);
-       for (i = 0; i < r; i++) {
-               printf ("%02x ", in[i]);
-       }
-       if (r) printf("\n");
-       for (i = 0; i < r; i++) {
-               printf ("%c", isalnum(in[i]) ? in[i] : '.');
-       }
-       if (r) printf("\n");
-}
+// static struct usb_bus *busses;
+static usb_dev_handle *udev;
+static void garmin_usb_scan(libusb_unit_data *, int);
 
-int
-gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
+static int
+gusb_libusb_send(const garmin_usb_packet *opkt, size_t sz)
 {
        int r;
+       
+       r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_B);
 
-        r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_I);
-        if (gps_show_bytes) {
-               dump ("Sent", &opkt->dbuf[0], r);
-       }
-       if (r != sz) {
+       if (r != (int) sz) {
                fprintf(stderr, "Bad cmdsend r %d sz %d\n", r, sz);
                if (r < 0) {
                        fatal("usb_bulk_write failed. '%s'\n", 
@@ -99,42 +74,37 @@ gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
        return r;
 }
 
-int
-gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
+static int
+gusb_libusb_get(garmin_usb_packet *ibuf, size_t sz)
 {
        unsigned char *buf = &ibuf->dbuf[0];
-       unsigned char *obuf = buf;
-       int r = -1, tsz = 0;
+       int r = -1;
 
        r = usb_interrupt_read(udev, gusb_intr_in_ep, (char *) buf, sz, TMOUT_I);
+       return r;
+}
 
-       tsz = r;
-
-        if (gps_show_bytes) {
-               int i;
-                const char *m1, *m2;
-                printf("RX [%d]:", tsz);
-                for(i=0;i<tsz;i++)
-                        GPS_Diag("%02x ", obuf[i]);
-                for(i=0;i<tsz;i++)
-                        GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
+static int
+gusb_libusb_get_bulk(garmin_usb_packet *ibuf, size_t sz)
+{
+       int r;
+       unsigned char *buf = &ibuf->dbuf[0];
 
-                m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2);
-                GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
-                printf("\n");
-        }
+       r = usb_bulk_read(udev, gusb_bulk_in_ep, (char *) buf, sz, TMOUT_B);
 
-       return (r);
+       return r;
 }
 
-void
-garmin_usb_teardown(void)
+
+static int
+gusb_teardown(const char *pname)
 {
        if (udev) {
                usb_release_interface(udev, 0);
                usb_close(udev);
                udev = NULL;
        }
+       return 0; 
 }
 
 void
@@ -143,11 +113,10 @@ garmin_usb_start(struct usb_device *dev)
        int i;
 
        if (udev) return;
-
        /*
-        * Linux _requires_ the reset.   OSX doesn't work if we DO reset it.
-        * I really should study this more, but for now, we'll just avoid the
-        * reset on Apple's OSX.
+        * Linux _requires_ the reset.   OSX doesn't work if we 
+        * DO reset it.  I really should study this more, but for 
+        * now, we'll just avoid the reset on Apple's OSX.
         */
 #if !defined (__APPLE__)
        udev = usb_open(dev);
@@ -156,21 +125,21 @@ garmin_usb_start(struct usb_device *dev)
 #endif /* APPLE */
 
        udev = usb_open(dev);
-       atexit(garmin_usb_teardown);
+       atexit((void(*)())gusb_teardown);
+
        if (!udev) { fatal("usb_open failed\n"); }
        /*
         * Hrmph.  No iManufacturer or iProduct headers....
         */
        if (usb_set_configuration(udev, 1) < 0) {
-               fatal("usb_set_configuration failed\n");
+               fatal("usb_set_configuration failed: %s\n", usb_strerror());
        }
 
        if (usb_claim_interface(udev, 0) < 0) {
-//             abort();
+               fatal("Claim interfaced failed: %s\n", usb_strerror());
        }
 
 
-
        for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) {
                struct usb_endpoint_descriptor * ep;
                ep = &dev->config->interface->altsetting->endpoint[i];
@@ -194,49 +163,22 @@ garmin_usb_start(struct usb_device *dev)
         * that loop without non-zero values for all three, we're hosed.
         */
        if (gusb_intr_in_ep && gusb_bulk_in_ep && gusb_bulk_out_ep) {
-               garmin_usb_syncup();
-       } else {
-               fatal("Could not identify endpoints on USB device.\nFound endpoints Intr In %d Bulk Out %d Bulk In %d\n", gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep);
+               gusb_syncup();
+               return;
        }
 
-       return;
-}
-
-void
-garmin_usb_syncup(void)
-{
-       int maxct = 5;
-       int maxtries;
-
-       for (maxtries = maxct; maxtries; maxtries--) {
-
-                le_write16(&iresp.gusb_pkt.pkt_id, 0);
-                le_write32(&iresp.gusb_pkt.datasz, 0);
-                le_write32(&iresp.gusb_pkt.databuf, 0);
-
-               gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
-               gusb_cmd_get(&iresp, sizeof(iresp));
-
-                if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) &&
-                        (le_read32(iresp.gusb_pkt.datasz) == 4)) {
-                       if (gps_show_bytes) {
-                               fprintf(stderr, "Synced in %d\n", maxct - maxtries);
-                       }
-//                     fprintf(stderr, "Unit number %u\n", iresp[15] << 24 | iresp[14] << 16 | iresp[13] << 8 | iresp[12]);
-                       return;
-               }
-       }
-return;
-       fatal("Cannot sync up with receiver\n");
+       fatal("Could not identify endpoints on USB device.\n"
+               "Found endpoints Intr In 0x%x Bulk Out 0x%x Bulk In %0xx\n", 
+               gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep);
 }
 
 static
-void garmin_usb_scan(void)
+void garmin_usb_scan(libusb_unit_data *lud, int req_unit_number)
 {
-       int initted = 0;
+       int found_devices = 0;
        struct usb_bus *bus;
 
-       for (bus = busses; bus; bus = bus->next) {
+       for (bus = lud->busses; bus; bus = bus->next) {
                struct usb_device *dev;
 
                for (dev = bus->devices; dev; dev = dev->next) {
@@ -245,14 +187,58 @@ void garmin_usb_scan(void)
                         * we just take the easy way out for now.
                         */
                        if (dev->descriptor.idVendor == GARMIN_VID) {
-                               garmin_usb_start(dev);  
-                               initted++;
+                               /* Nuvi */
+                               if (dev->descriptor.idProduct == 0x19) 
+                                       continue;
+                               if (req_unit_number < 0) {
+                                       garmin_usb_start(dev);  
+                                       gusb_teardown(NULL);
+                               } else 
+                               if (req_unit_number == found_devices)
+                                       garmin_usb_start(dev);  
+                               found_devices++;
                        }
                }
        }
 
-       if (0 == initted) {
+       if (req_unit_number < 0) {
+               gusb_list_units();
+               exit (0);
+       }
+       if (0 == found_devices) {
                fatal("Found no Garmin USB devices.\n");
        }
 }
+
+static gusb_llops_t libusb_llops = {
+       gusb_libusb_get,
+       gusb_libusb_get_bulk,
+       gusb_libusb_send,
+       gusb_teardown
+};
+
+int
+gusb_init(const char *portname, gpsdevh **dh)
+{
+       int req_unit_number = 0;
+       libusb_unit_data *lud = xcalloc(sizeof (libusb_unit_data), 1);
+       *dh = (gpsdevh*) lud;
+
+// usb_set_debug(99);
+       usb_init();
+       gusb_register_ll(&libusb_llops);
+
+       /* if "usb:N", read "N" to be the unit number. */
+       if (strlen(portname) > 4) {
+               req_unit_number = atoi(portname + 4);
+       }
+
+       usb_find_busses();
+       usb_find_devices();
+       lud->busses = usb_get_busses();
+       garmin_usb_scan(lud, req_unit_number);
+
+       return 1;
+}
+
 #endif /* HAVE_LIBUSB */
index ed070c08a5788c6f365fcf0c8199f41c814cf6c6..b3141dc4354b304545e3472d7384286a0a782539 100644 (file)
@@ -5,6 +5,7 @@
 ** @version 1.0 
 ** @modified December 28th 1999 Alan Bleasby. First version
 ** @modified June 29th 2000 Alan Bleasby. NMEA additions
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -23,7 +24,6 @@
 ** Boston, MA  02111-1307, USA.
 ********************************************************************/
 #include "gps.h"
-#include "garminusb.h"
 #include <stdlib.h>
 #include <errno.h>
 #include <stdio.h>
@@ -63,7 +63,6 @@ GPS_PPacket GPS_Packet_New(void)
 }
 
 
-
 /* @func GPS_Packet_Del ***********************************************
 **
 ** Packet destructor
index 8124370929b824b4e4122e311ce529223aec8e58..fabdfd89a464265182499049ec07f833bcf6283d 100644 (file)
@@ -4,6 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -36,7 +37,7 @@ static int32 gps_n_tag_unknown = 0;
 struct COMMANDDATA COMMAND_ID[2]=
 {
     {
-       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32
+       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32,92,117,121
     }
     ,
     {
index 60cc3c32c9d8ee1db0c4510a0174fc575ae964f8..f9542799d494388c7d81a59891a6a5b947af338c 100644 (file)
@@ -33,6 +33,7 @@ struct LINKDATA
     UC Pid_Protocol_Array;
     UC Pid_Product_Rqst;
     UC Pid_Product_Data;
+    UC Pid_Wpt_Cat_Data;
 }
 ;
 
@@ -63,7 +64,9 @@ struct COMMANDDATA
     UC Cmnd_Turn_Off_Pwr;
     UC Cmnd_Start_Pvt_Data;
     UC Cmnd_Stop_Pvt_Data;
+    UC Cmnd_FlightBook_Transfer;
     UC Cmnd_Transfer_Lap;
+    UC Cmnd_Transfer_Wpt_Cats;
 }
 ;
 
@@ -76,6 +79,11 @@ struct COMMANDDATA
 #define pA100 100
 int32 gps_waypt_transfer;
 
+/*
+ * Waypoint category transfer protocol
+ */
+#define pA101 101
+int32 gps_category_transfer;
 
 /*
  * Route Transfer Protocol
@@ -90,6 +98,7 @@ int32 gps_route_transfer;
 #define pA300 300
 #define pA301 301
 #define pA302 302
+#define pA304 304
 int32 gps_trk_transfer;
 
 /*
@@ -157,6 +166,11 @@ int32 gps_lap_transfer;
 int32 gps_rte_type;
 int32 gps_waypt_type;
 
+/*
+ * Waypoint category types
+ */
+#define pD120 120
+int32 gps_category_type;
 
 /*
  * Rte Header Type
@@ -181,6 +195,7 @@ int32 gps_rte_link_type;
 #define pD301 301
 #define pD302 302
 #define pD303 303
+#define pD304 304
 int32 gps_trk_type;
 
 
index 2d2f2d153fb2a77b0cb4b9862bfe03a84cc3f19f..587f15c6fa4a05c02510cd64c58f797336cf0f72 100644 (file)
@@ -4,6 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -22,7 +23,7 @@
 ** Boston, MA  02111-1307, USA.
 ********************************************************************/
 #include "gps.h"
-#include "gpsusbint.h"
+#include "gpsserial.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
@@ -57,7 +58,7 @@ time_t GPS_Time_Now(void)
 
 
 
-/* @func GPS_Packet_Read ***********************************************
+/* @func GPS_Serial_Packet_Read ***********************************************
 **
 ** Read a packet
 **
@@ -67,7 +68,7 @@ time_t GPS_Time_Now(void)
 ** @return [int32] number of bytes read
 **********************************************************************/
 
-int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
+int32 GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet)
 {
     time_t start;
     int32  n;
@@ -84,10 +85,6 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
     isDLE = gpsFalse;
     p = (*packet)->data;
 
-    if (gps_is_usb) {
-           return GPS_Packet_Read_usb(fd, packet);
-    }
-    
     start = GPS_Time_Now();
     GPS_Diag("Rx Data:");
     while(GPS_Time_Now() < start+GPS_TIME_OUT)
@@ -109,7 +106,7 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
                (*packet)->dle = u;
                if(u != DLE)
                {
-                   (void) fprintf(stderr,"GPS_Packet_Read: No DLE\n");
+                   (void) fprintf(stderr,"GPS_Packet_Read: No DLE.  Data received, but probably not a garmin packet.\n");
                    (void) fflush(stderr);
                    return 0;
                }
@@ -166,6 +163,14 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
                    }
                    
                    m1 = Get_Pkt_Type((*packet)->type, (*packet)->data[0], &m2);
+                   if (gps_show_bytes) {
+                       GPS_Diag(" ");
+                       for (i = 0; i < (*packet)->n; i++) {
+                          char c = (*packet)->data[i];
+                          GPS_Diag("%c", isalnum(c) ? c  : '.');
+                       }
+                       GPS_Diag(" ");
+                   }
                    GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
                    return (*packet)->n;
                }
@@ -175,7 +180,7 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
     }
     
            
-    GPS_Error("GPS_Packet_Read: Time-out");
+    GPS_Error("GPS_Packet_Read: Timeout.  No data received.");
     gps_errno = SERIAL_ERROR;
 
     return 0;
@@ -194,13 +199,9 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
 ** @return [int32] true if ACK
 **********************************************************************/
 
-int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec)
+int32 GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec)
 {
-    if (gps_is_usb) {
-           return 1;
-    }
-
-    if(!GPS_Packet_Read(fd, rec))
+    if(!GPS_Serial_Packet_Read(fd, rec))
        return 0;
 
     if(LINK_ID[0].Pid_Ack_Byte != (*rec)->type)
index 5abd56cfa1ad2b40a3b0a86234e142720692d9d9..17f3bd85239c5dbad4cac0732341f54b6e9f2bd4 100644 (file)
@@ -8,14 +8,10 @@ extern "C"
 
 
 #include "gps.h"
-#include <time.h>
 
 time_t GPS_Time_Now(void);
-int32  GPS_Packet_Read(int32 fd, GPS_PPacket *packet);
-int32  GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet);
-int32  GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec);
-int32  ajb(int32 fd);
-
+int32  GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet);
+int32  GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
 
 #endif
 
index 82755907178f5698ab21aa83a85f4d7be78a0a4a..7203313c65f332174bd551a4ce5537dc8c3055e6 100644 (file)
@@ -4,6 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -24,8 +25,8 @@
 #include "gps.h"
 
 
-static int32 GPS_A600_Rqst(int32 fd, time_t Time);
-static int32 GPS_A700_Rqst(int32 fd, double lat, double lon);    
+static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time);
+static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon);    
 
 
 
@@ -39,7 +40,7 @@ static int32 GPS_A700_Rqst(int32 fd, double lat, double lon);
 ** @return [int32] true if OK
 ************************************************************************/
 
-int32 GPS_Rqst_Send_Time(int32 fd, time_t Time)
+int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time)
 {
     time_t ret=0;
 
@@ -67,7 +68,7 @@ int32 GPS_Rqst_Send_Time(int32 fd, time_t Time)
 **
 ** @return [int32] success
 ************************************************************************/
-static int32 GPS_A600_Rqst(int32 fd, time_t Time)
+static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
@@ -110,7 +111,7 @@ static int32 GPS_A600_Rqst(int32 fd, time_t Time)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon)
+int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon)
 {
     int32 ret=0;
 
@@ -139,7 +140,7 @@ int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon)
 **
 ** @return [int32] success
 ************************************************************************/
-static int32 GPS_A700_Rqst(int32 fd, double lat, double lon)
+static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon)
 {
     GPS_PPacket tra;
     GPS_PPacket rec;
index c6398ecd005cdaecf8d711bc57b6a02c25c3c668..ec016958614d838cdbab4d0d68de19d138256916 100644 (file)
@@ -9,8 +9,8 @@ extern "C"
 
 #include "gps.h"
 
-int32 GPS_Rqst_Send_Time(int32 fd, time_t Time);
-int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon);
+int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time);
+int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon);
 
 
 #endif
index b32ba2a27f8e12eafb277aef399a838cbe7797bc..d863683d9fc0b00ac1109b45d88cf4c980f27270 100644 (file)
@@ -4,6 +4,7 @@
 ** @author Copyright (C) 1999 Alan Bleasby
 ** @version 1.0 
 ** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -22,7 +23,7 @@
 ** Boston, MA  02111-1307, USA.
 ********************************************************************/
 #include "gps.h"
-#include "gpsusbint.h"
+#include "gpsserial.h"
 
 #include <stdio.h>
 #include <errno.h>
@@ -41,7 +42,7 @@
 ** @return [void]
 ************************************************************************/
 
-void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
+void GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
 {
     UC *p;
     UC *q;
@@ -53,11 +54,6 @@ void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
     p = data;
     q = (*packet)->data;
 
-    if (gps_is_usb) {
-           GPS_Make_Packet_usb(packet, type, data, n);
-           return;
-    }
-    
     (*packet)->dle   = DLE;
     (*packet)->edle  = DLE;
     (*packet)->etx   = ETX;
@@ -130,13 +126,11 @@ DiagS(void *buf, size_t sz)
 ** @return [int32] number of bytes in the packet
 ************************************************************************/
 
-int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet)
+int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet)
 {
     size_t ret;
     const char *m1, *m2;
-
-    if (gps_is_usb) 
-           return GPS_Write_Packet_usb(fd, packet);
+    
 
     GPS_Diag("Tx Data:");
     Diag(&packet->dle, 3);    
@@ -202,13 +196,10 @@ int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec)
+int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec)
 {
     UC data[2];
 
-    if (gps_is_usb) 
-           return 1;
-    
     GPS_Util_Put_Short(data,(US)(*rec)->type);
     GPS_Make_Packet(tra,LINK_ID[0].Pid_Ack_Byte,data,2);
     if(!GPS_Write_Packet(fd,*tra))
index f048fdec8a81c9c0d66e9e1fd63030c1a79825da..edd3f5b0daa58482f653e5d78821fe01ae87bc58 100644 (file)
@@ -11,12 +11,11 @@ extern "C"
 
 #define GPS_ARB_LEN 1024
 
-UC gps_sendbuf[GPS_ARB_LEN];
+void   GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n);    
+int32  GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32  GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
 
 void   GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n);    
-int32  GPS_Write_Packet(int32 fd, GPS_PPacket packet);
-int32  GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec);
-
 
 
 #endif
index 0da43cf2e34c14869e0d0de2713abe5dd6fdb4de..0496374a6268f15681b41fe639d3c42dae05c6ed 100644 (file)
@@ -5,6 +5,7 @@
 ** @version 1.0
 ** @modified December 28th 1999 Alan Bleasby. First version
 ** @modified June 29th 2000 Alan Bleasby. NMEA additions
+** @modified Copyright (C) 2006 Robert Lipe
 ** @@
 ** 
 ** This library is free software; you can redistribute it and/or
@@ -23,7 +24,7 @@
 ** Boston, MA  02111-1307, USA.
 ********************************************************************/
 #include "gps.h"
-#include "garminusb.h"
+#include "gpsserial.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -56,18 +57,12 @@ char *rxdata[] = {
 #if defined (__WIN32__) || defined (__CYGWIN__)
 
 #include <windows.h>
-/*
- *  Rather than teaching the rest of this code about Windows serial APIs
- *  we'll weenie out, violate good layering, and just keep our handle
- *  internal.   This means we ignore that 'fd' number that gets passed in.
- */
-
-static HANDLE comport;
+#include "gpsserial_win.h"
 
 /*
  * Display an error from the serial subsystem.
  */
-void GPS_Serial_Error(char *mb, ...)
+void GPS_Serial_Error(const char *mb, ...)
 {
        va_list ap;
        char msg[200];
@@ -75,7 +70,6 @@ void GPS_Serial_Error(char *mb, ...)
        int b;
 
        va_start(ap, mb);
-//     strcpy(msg, msg);
        b = vsnprintf(msg, sizeof(msg), mb, ap);
        s = msg + b;
        *s++ = ':';
@@ -86,18 +80,13 @@ void GPS_Serial_Error(char *mb, ...)
        GPS_Error(msg);
 }
 
-int32 GPS_Serial_On(const char *port, int32 *fd)
+int32 GPS_Serial_On(const char *port, gpsdevh **dh)
 {
        DCB tio;
        COMMTIMEOUTS timeout;
-
-       if (gps_is_usb) {
-           switch (gusb_open(port)) {
-                   case 0: return 0;
-                   case 1: return 1;
-                   case 2: exit(0);
-           }
-       }
+       HANDLE comport;
+       win_serial_data *wsd = xcalloc(sizeof (win_serial_data), 1);
+       *dh = (gpsdevh*) wsd;
 
        comport = CreateFile(port, GENERIC_READ|GENERIC_WRITE, 0, NULL,
                                          OPEN_EXISTING, 0, NULL);
@@ -156,35 +145,31 @@ int32 GPS_Serial_On(const char *port, int32 *fd)
                gps_errno = SERIAL_ERROR;
                return 0;
        }
-       *fd = 1;
+       wsd->comport = comport;
        return 1;
 }
 
-int32 GPS_Serial_Off(const char *port, int32 fd)
+int32 GPS_Serial_Off(gpsdevh *dh)
 {
-       if (gps_is_usb) {
-               gusb_close(port);
-       } else {
-               CloseHandle(comport);
-               comport = INVALID_HANDLE_VALUE;
-       }
+       win_serial_data *wsd = (win_serial_data*)dh;
+       CloseHandle(wsd->comport);
+       wsd->comport = INVALID_HANDLE_VALUE;
+       xfree(wsd);
        return 1;
 }
 
-int32 GPS_Serial_Chars_Ready(int32 fd)
+int32 GPS_Serial_Chars_Ready(gpsdevh *dh)
 {
        COMSTAT lpStat;
        DWORD lpErrors;
+       win_serial_data *wsd = (win_serial_data*)dh;
 
-       ClearCommError(comport, &lpErrors, &lpStat);
+       ClearCommError(wsd->comport, &lpErrors, &lpStat);
        return (lpStat.cbInQue > 0);
 }
 
-int32 GPS_Serial_Wait(int32 fd)
+int32 GPS_Serial_Wait(gpsdevh *fd)
 {
-
-       if (gps_is_usb) return 1;
-
        /* Wait a short time before testing if data is ready.
         * The GPS II, in particular, has a noticable time responding
         * with a response to the device inquiry and if we give up on this
@@ -196,13 +181,14 @@ int32 GPS_Serial_Wait(int32 fd)
        return GPS_Serial_Chars_Ready(fd);
 }
 
-int32 GPS_Serial_Flush(int32 fd)
+int32 GPS_Serial_Flush(gpsdevh *fd)
 {
        return 1;
 }
 
-int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size)
+int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size)
 {
+       win_serial_data *wsd = (win_serial_data*)dh;
        DWORD len;
 
        /* 
@@ -215,34 +201,29 @@ int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size)
        if (size == 0) {
                return 0;
        }
-       WriteFile (comport, obuf, size, &len, NULL);
+       WriteFile (wsd->comport, obuf, size, &len, NULL);
        if (len != (DWORD) size) {
                fatal ("Write error.   Wrote %d of %d bytes.\n", len, size);
        }
        return len;
 }
 
-int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size)
+int32 GPS_Serial_Read(gpsdevh * dh, void *ibuf, int size)
 {
        DWORD cnt  = 0;
+       win_serial_data *wsd = (win_serial_data*)dh;
 
-       ReadFile(comport, ibuf, size, &cnt, NULL);
+       ReadFile(wsd->comport, ibuf, size, &cnt, NULL);
        return cnt;
 }
 
-int32 GPS_Serial_Close(int32 fd, const char *port)
-{
-       return 1;
-}
-
 #else
 
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <termios.h>
 #include <unistd.h>
-
-static struct termios gps_ttysave;
+#include "gpsserial_posix.h"
 
 /* @func GPS_Serial_Restoretty ***********************************************
 **
@@ -253,32 +234,12 @@ static struct termios gps_ttysave;
 ** @return [int32] false upon error
 ************************************************************************/
 
-int32 GPS_Serial_Savetty(const char *port)
+static int32 GPS_Serial_Savetty(int32 fd)
 {
-    int32 fd;
-
-    if (gps_is_usb) return 1;
-    
-    if((fd = open(port, O_RDWR))==-1)
-    {
-       perror("open");
-       gps_errno = SERIAL_ERROR;
-       GPS_Error("SERIAL: Cannot open serial port '%s'", port);
-       return 0;
-    }
-    
     if(tcgetattr(fd,&gps_ttysave)==-1)
     {
-       perror("tcgetattr");
        gps_errno = HARDWARE_ERROR;
-       GPS_Error("SERIAL: tcgetattr error");
-       return 0;
-    }
-
-    if(!GPS_Serial_Close(fd,port))
-    {
-       gps_errno = SERIAL_ERROR;
-       GPS_Error("GPS_Serial_Savetty: Close error");
+       GPS_Serial_Error("SERIAL: tcgetattr error");
        return 0;
     }
 
@@ -295,32 +256,19 @@ int32 GPS_Serial_Savetty(const char *port)
 ** @return [int32] false upon error
 ************************************************************************/
 
-int32 GPS_Serial_Restoretty(const char *port)
+static int32 GPS_Serial_Restoretty(int fd)
 {
-    int32 fd;
-
-    if (gps_is_usb) return 1;
-    
-    if((fd = open(port, O_RDWR))==-1)
-    {
-       perror("open");
-       gps_errno = HARDWARE_ERROR;
-       GPS_Error("SERIAL: Cannot open serial port '%s'", port);
-       return 0;
-    }
-    
     if(tcsetattr(fd, TCSAFLUSH, &gps_ttysave)==-1)
     {
-       perror("ioctl");
        gps_errno = HARDWARE_ERROR;
-       GPS_Error("SERIAL: tcsetattr error");
+       GPS_Serial_Error("SERIAL: tcsetattr error");
        return 0;
     }
 
     return 1;
 }
 
-
+#endif
 
 /* @func GPS_Serial_Open ***********************************************
 **
@@ -332,9 +280,10 @@ int32 GPS_Serial_Restoretty(const char *port)
 ** @return [int32] false upon error
 ************************************************************************/
 
-int32 GPS_Serial_Open(int32 *fd, const char *port)
+int32 GPS_Serial_Open(gpsdevh *dh, const char *port)
 {
     struct termios tty;
+    posix_serial_data *psd = (posix_serial_data *)dh;
     
     /*
      * This originally had O_NDELAY | O_NOCTTY in here, but this
@@ -342,21 +291,20 @@ int32 GPS_Serial_Open(int32 *fd, const char *port)
      * and the rest of the code doesn't _REALLY_ handle the partial 
      * write/retry case anyway.  - robertl
      */
-    if((*fd = open(port, O_RDWR))==-1)
+    if((psd->fd = open(port, O_RDWR))==-1)
     {
-       perror("open");
-       GPS_Error("SERIAL: Cannot open serial port '%s'", port);
+       GPS_Serial_Error("XSERIAL: Cannot open serial port '%s'", port);
        gps_errno = SERIAL_ERROR;
        return 0;
     }
 
-    if(tcgetattr(*fd,&tty)==-1)
+    if(tcgetattr(psd->fd,&psd->gps_ttysave)==-1)
     {
-       perror("tcgetattr");
-       GPS_Error("SERIAL: tcgetattr error");
-       gps_errno = SERIAL_ERROR;
+       gps_errno = HARDWARE_ERROR;
+       GPS_Serial_Error("SERIAL: tcgetattr error");
        return 0;
     }
+    tty = psd->gps_ttysave;
 
     tty.c_cflag &= ~(CSIZE);
     tty.c_cflag |= (CREAD | CS8 | CLOCAL);
@@ -369,18 +317,40 @@ int32 GPS_Serial_Open(int32 *fd, const char *port)
     tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;
 
-    if(tcsetattr(*fd,TCSANOW,&tty)==-1)
+    if(tcsetattr(psd->fd,TCSANOW,&tty)==-1)
     {
-       perror("tcsetattr");
-       GPS_Error("SERIAL: tcsetattr error");
+       GPS_Serial_Error("SERIAL: tcsetattr error");
        return 0;
     }
 
     return 1;
 }
 
-int32 GPS_Serial_Read(int32 handle, void *ibuf, int size)
+/*
+ * Display an error from the serial subsystem.
+ */
+void GPS_Serial_Error(const char *mb, ...)
+{
+       va_list ap;
+       char msg[200];
+       char *s;
+       int b;
+
+       va_start(ap, mb);
+       b = vsnprintf(msg, sizeof(msg), mb, ap);
+       s = msg + b;
+       *s++ = ':';
+       *s++ = ' ';
+
+//     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, 
+//                     GetLastError(), 0, s, sizeof(msg) - b - 2, 0 );
+        strcat(msg, strerror(errno));
+       GPS_Error(msg);
+}
+
+int32 GPS_Serial_Read(gpsdevh *dh, void *ibuf, int size)
 {
+       posix_serial_data *psd = (posix_serial_data *)dh;
 #if GARMULATOR
        static int l;
        static char *rp;
@@ -402,13 +372,14 @@ int32 GPS_Serial_Read(int32 handle, void *ibuf, int size)
        return 1;
 
 #else
-       return read(handle, ibuf, size);
+       return read(psd->fd, ibuf, size);
 #endif
 }
 
-int32 GPS_Serial_Write(int32 handle, const void *obuf, int size)
+int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size)
 {
-       return write(handle, obuf, size);
+       posix_serial_data *psd = (posix_serial_data *)dh;
+       return write(psd->fd, obuf, size);
 }
 
 
@@ -420,14 +391,13 @@ int32 GPS_Serial_Write(int32 handle, const void *obuf, int size)
 **
 ** @return [int32] false upon error
 ************************************************************************/
-int32 GPS_Serial_Flush(int32 fd)
+int32 GPS_Serial_Flush(gpsdevh *fd)
 {
-    if (gps_is_usb) return 1;
-    
-    if(tcflush(fd,TCIOFLUSH))
+    posix_serial_data *psd = (posix_serial_data *)fd;
+
+    if(tcflush(psd->fd,TCIOFLUSH))
     {
-       perror("tcflush");
-       GPS_Error("SERIAL: tcflush error");
+       GPS_Serial_Error("SERIAL: tcflush error");
        gps_errno = SERIAL_ERROR;
        return 0;
     }
@@ -447,14 +417,20 @@ int32 GPS_Serial_Flush(int32 fd)
 ** @return [int32] false upon error
 ************************************************************************/
 
-int32 GPS_Serial_Close(int32 fd, const char *port)
+int32 GPS_Serial_Close(gpsdevh *fd)
 {
-    if (gps_is_usb)  return 1;
+    posix_serial_data *psd = (posix_serial_data *)fd;
 
-    if(close(fd)==-1)
+    if(tcsetattr(psd->fd, TCSAFLUSH, &psd->gps_ttysave)==-1)
     {
-       perror("close");
-       GPS_Error("SERIAL: Error closing serial port");
+       gps_errno = HARDWARE_ERROR;
+       GPS_Serial_Error("SERIAL: tcsetattr error");
+       return 0;
+    }
+
+    if(close(psd->fd)==-1)
+    {
+       GPS_Serial_Error("SERIAL: Error closing serial port");
        gps_errno = SERIAL_ERROR;
        return 0;
     }
@@ -472,10 +448,13 @@ int32 GPS_Serial_Close(int32 fd, const char *port)
 ** @return [int32] true if chars waiting
 ************************************************************************/
 
-int32 GPS_Serial_Chars_Ready(int32 fd)
+int32 GPS_Serial_Chars_Ready(gpsdevh *dh)
 {
     fd_set rec;
     struct timeval t;
+    posix_serial_data *psd = (posix_serial_data *)dh;
+    int32 fd = psd->fd;
+
 #if GARMULATOR
     static foo;
     /* Return sporadic reads just to torment the rest of the code. */
@@ -510,21 +489,20 @@ int32 GPS_Serial_Chars_Ready(int32 fd)
 ** @return [int32] true if serial chars waiting
 ************************************************************************/
 
-int32 GPS_Serial_Wait(int32 fd)
+int32 GPS_Serial_Wait(gpsdevh *dh)
 {
     fd_set rec;
     struct timeval t;
-
-    if (gps_is_usb) return 1;
+    posix_serial_data *psd = (posix_serial_data *)dh;
 
     FD_ZERO(&rec);
-    FD_SET(fd,&rec);
+    FD_SET(psd->fd,&rec);
 
     t.tv_sec  = 0;
-    t.tv_usec = usecDELAY;
+    t.tv_usec = 180000;        /* Microseconds before GPS sends A001 */
 
-    (void) select(fd+1,&rec,NULL,NULL,&t);
-    if(FD_ISSET(fd,&rec))
+    (void) select(psd->fd+1,&rec,NULL,NULL,&t);
+    if(FD_ISSET(psd->fd,&rec))
        return 1;
 
     return 0;
@@ -542,19 +520,12 @@ int32 GPS_Serial_Wait(int32 fd)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Serial_On(const char *port, int32 *fd)
+int32 GPS_Serial_On(const char *port, gpsdevh **dh)
 {
-    if (gps_is_usb) {
-           return gusb_init(port);
-    }
-    if(!GPS_Serial_Savetty(port))
-    {
-       GPS_Error("Cannot access serial port '%s'", port);
-       gps_errno = SERIAL_ERROR;
-       return 0;
-    }
+    posix_serial_data *psd = xcalloc(sizeof (posix_serial_data), 1);
+    *dh = (gpsdevh*) psd;
     
-    if(!GPS_Serial_Open(fd,port))
+    if(!GPS_Serial_Open((gpsdevh *) psd,port))
     {
        GPS_Error("Cannot open serial port '%s'", port);
        gps_errno = SERIAL_ERROR;
@@ -576,22 +547,17 @@ int32 GPS_Serial_On(const char *port, int32 *fd)
 ** @return [int32] success
 ************************************************************************/
 
-int32 GPS_Serial_Off(const char *port, int32 fd)
+int32 GPS_Serial_Off(gpsdevh *dh)
 {
-    if(!GPS_Serial_Close(fd,port))
+
+    if(!GPS_Serial_Close(dh))
     {
        GPS_Error("Error Closing port");
        gps_errno = HARDWARE_ERROR;
        return 0;
     }
+    dh = NULL;
     
-    if(!GPS_Serial_Restoretty(port))
-    {
-       GPS_Error("Error restoring port");
-       gps_errno = HARDWARE_ERROR;
-       return 0;
-    }
-
     return 1;
 }
 
index 7726bfbbcb63d403150d89595c3cf5510d2087a8..bf245105ec9034efcddcd8eda1f1fc95295a768a 100644 (file)
@@ -11,20 +11,22 @@ extern "C"
 
 #define usecDELAY 180000       /* Microseconds before GPS sends A001 */
 
-int32  GPS_Serial_Chars_Ready(int32 fd);
-int32  GPS_Serial_Close(int32 fd, const char *port);
-int32  GPS_Serial_Open(int32 *fd, const char *port);
-int32  GPS_Serial_Open_NMEA(int32 *fd, const char *port);
-int32  GPS_Serial_Restoretty(const char *port);
-int32  GPS_Serial_Savetty(const char *port);
-int32  GPS_Serial_On(const char *port, int32 *fd);
-int32  GPS_Serial_Off(const char *port, int32 fd);
-int32  GPS_Serial_Wait(int32 fd);
-int32  GPS_Serial_Flush(int32 fd);
-int32  GPS_Serial_On_NMEA(const char *port, int32 *fd);
-int32  GPS_Serial_Read(int32 ignored, void *ibuf, int size);
-int32  GPS_Serial_Write(int32 ignored, const void *obuf, int size);
-void   GPS_Serial_Error(char *hdr, ...);
+int32  GPS_Serial_Chars_Ready(gpsdevh * fd);
+// int32  GPS_Serial_Close(int32 fd, const char *port);
+// int32  GPS_Serial_Open(int32 *fd, const char *port);
+// int32  GPS_Serial_Open_NMEA(int32 *fd, const char *port);
+// int32  GPS_Serial_Restoretty(const char *port);
+// int32  GPS_Serial_Savetty(const char *port);
+int32  GPS_Serial_On(const char *port, gpsdevh **fd);
+int32  GPS_Serial_Off(gpsdevh *fd);
+int32  GPS_Serial_Wait(gpsdevh *fd);
+int32  GPS_Serial_Flush(gpsdevh *fd);
+// int32  GPS_Serial_On_NMEA(const char *port, gpsdevh **fd);
+int32  GPS_Serial_Read(gpsdevh *fd, void *ibuf, int size);
+int32  GPS_Serial_Write(gpsdevh *fd, const void *obuf, int size);
+int32  GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32  GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+void   GPS_Serial_Error(const char *hdr, ...);
 
 
 #endif
index 38dfbfb6279ede2d48e4f6c0e428664bb9f67a23..94e6adac011d4531602f6684c6c417cbda4907d4 100644 (file)
 
  */
 
-#include <usb.h>
 #include "gps.h"
 #include "garminusb.h"
-
+#include "gpsusbcommon.h"
 
 /*
  * This receive logic is a little convoluted as we go to some efforts here
@@ -36,17 +35,47 @@ enum {
        rs_frombulk
 } receive_state;
 
+static gusb_llops_t *gusb_llops;
+
+/* Decide when to truncate packets for debug output */
+#define DEBUG_THRESH  ((global_opts.debug_level < 5) && (i > 10))
+
+/* Called from OS layer to register its low-level entry points. */
+void
+gusb_register_ll(gusb_llops_t *p)
+{
+       gusb_llops = p;
+}
+
 int
-gusb_close(const char *portname)
+gusb_close(gpsdevh *dh)
 {
        garmin_usb_packet scratch;
+
+       memset(&scratch, 0, sizeof(scratch));
+
        switch (receive_state) {
        case rs_frombulk:
                gusb_cmd_get(&scratch, sizeof(scratch));
                break;
+       default:
+               break;
+       }
+
+       gusb_llops->llop_close(dh);
+       return 1;
+
+#if BOOGER
+       garmin_usb_packet scratch = {0};
+abort();
+       switch (receive_state) {
+       case rs_frombulk:
+               gusb_cmd_get(dh, &scratch, sizeof(scratch));
+               break;
        }
 
        return 1;
+#endif
 }
 
 
@@ -55,18 +84,18 @@ gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
 {
        int rv;
        unsigned char *buf = (unsigned char *) &ibuf->dbuf;
-
+       int orig_receive_state;
 top:
+       orig_receive_state = receive_state;
        switch (receive_state) {
        case rs_fromintr:
-                       rv = gusb_cmd_get_os(ibuf, sz);
-                       break;
+               rv = gusb_llops->llop_get_intr(ibuf, sz);
+               break;
        case rs_frombulk:
-                       rv = gusb_cmd_get_os_bulk(ibuf, sz);
-                       if (rv == 0) {
-                               receive_state = rs_fromintr;
-                       }
-                       break;
+               rv = gusb_llops->llop_get_bulk(ibuf, sz);
+               break;
+       default:
+               fatal("Unknown receiver state %d\n", receive_state);
        }
 
        if (gps_show_bytes) {
@@ -76,21 +105,44 @@ top:
                GPS_Diag("RX (%s) [%d]:", 
                        receive_state == rs_fromintr ? "intr" : "bulk", rv);
 
-               for(i=0;i<rv;i++)
+               for(i=0;i<rv;i++) {
+                       if (DEBUG_THRESH) {
+                               GPS_Diag("[...]");
+                               break;
+                       }
                        GPS_Diag("%02x ", buf[i]);
+               }
 
-               for(i=0;i<rv;i++)
+               for(i=0;i<rv;i++) {
+                       if (DEBUG_THRESH) {
+                               GPS_Diag("[...]");
+                               break;
+                       }
                        GPS_Diag("%c", isalnum(buf[i])? buf[i] : '.');
+               }
 
                m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], 
                        ibuf->gusb_pkt.databuf[0], &m2);
+if ((rv == 0)  &&  (receive_state == rs_frombulk) ) {m1= "RET2INTR";m2=NULL;};
                GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
        }
 
-       if (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK) {
+       /* Adjust internal state and retry the read */
+       if ((rv > 0) && (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK)) {
                receive_state = rs_frombulk;
                goto top;
        }
+       /*
+        * If we were reading from the bulk pipe and we just got
+        * a zero request, adjust our internal state.
+        * It's tempting to retry the read here to hide this "stray"
+        * packet from our callers, but that only works when you know
+        * there's another packet coming.   That works in every case
+        * except the A000 discovery sequence.
+       */
+       if ((receive_state == rs_frombulk) && (rv <= 0)) {
+               receive_state = rs_fromintr;
+       }
 
        return rv;
 }
@@ -98,12 +150,12 @@ top:
 int 
 gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
 {
-       int rv, i;
+       unsigned int rv, i;
 
        unsigned char *obuf = (unsigned char *) &opkt->dbuf;
        const char *m1, *m2;
 
-       rv = gusb_cmd_send_os(opkt, sz);
+       rv = gusb_llops->llop_send(opkt, sz);
 
        if (gps_show_bytes) {
                GPS_Diag("TX [%d]:", sz);
@@ -129,36 +181,43 @@ gusb_list_units()
        
        for (i = 0; i < GUSB_MAX_UNITS; i++) {
                if (garmin_unit_info[i].serial_number) {
-                       printf("%d %u %s\n", i, 
+                       printf("%d %lu %lu %s\n", i, 
                                garmin_unit_info[i].serial_number,
+                               garmin_unit_info[i].unit_id,
                                garmin_unit_info[i].product_identifier
                        );
                }
        }
 }
 
-char * 
-gusb_id_unit(void
+void
+gusb_id_unit(struct garmin_unit_info *gu
 {
        static const char  oid[12] = 
                {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
        garmin_usb_packet iresp;
        int i;
-       char *rv = NULL;
 
        gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid));
 
        for (i = 0; i < 25; i++) {
                iresp.gusb_pkt.type = 0;
                if (gusb_cmd_get(&iresp, sizeof(iresp)) < 0) {
-                       return rv;
+                       return;
                }
                if (le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
-                       rv = strdup((char *) iresp.gusb_pkt.databuf+4);
+                       gu->product_identifier = xstrdup((char *) iresp.gusb_pkt.databuf+4);
+                       gu->unit_id = le_read16(iresp.gusb_pkt.databuf+0);
+                       gu->unit_version = le_read16(iresp.gusb_pkt.databuf+2);
                }
+               /* 
+                * My goodnesss, this is fragile.  During command syncup,
+                * we need to know if we're at the end.  The 0xfd packet
+                * is promised by Garmin engineering to be the last.  
+                */
+               if (le_read16(iresp.gusb_pkt.pkt_id) == 0xfd) return;
        }
-fatal("eek!");
-       
+       fatal("Unable to sync with Garmin USB device in %d attempts.", i);
 } 
 
 void
@@ -170,6 +229,11 @@ gusb_syncup(void)
        garmin_usb_packet iresp;
        int i;
 
+       /*
+        * This is our first communication with the unit.
+        */
+       receive_state = rs_fromintr;
+
        for(i = 0; i < 25; i++) {
                le_write16(&iresp.gusb_pkt.pkt_id, 0);
                le_write32(&iresp.gusb_pkt.datasz, 0);
@@ -182,7 +246,7 @@ gusb_syncup(void)
                        (le_read32(iresp.gusb_pkt.datasz) == 4)) {
                        unsigned serial_number = le_read32(iresp.gusb_pkt.databuf);
                        garmin_unit_info[unit_number].serial_number = serial_number;
-                       garmin_unit_info[unit_number].product_identifier = gusb_id_unit();
+                       gusb_id_unit(&garmin_unit_info[unit_number]);
 
                        unit_number++;
 
index 3a0e001375add0eacf3e25b4eec07378bce2c225..8d91da24a2edf597c756b334d490c09158ee38df 100644 (file)
@@ -3,7 +3,7 @@
     These symbols should not be publicly used.  They're "friend" functions
     of USB details internal to jeeps.
 
-    Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2005, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
 
  */
 
-int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet);
+int32 GPS_Packet_Read_usb(gpsdevh *fd, GPS_PPacket *packet, int eatbulk);
 void  GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n);
-int32 GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet);
+int32 GPS_Write_Packet_usb(gpsdevh *fd, GPS_PPacket packet);
 
index 14a12ccfc8325b02802dafc0ef9b59da1c99c552..1cdce1df2051c32e1fb783bcb8c769761be04ec7 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Decompose an incoming USB packet to make it look like a serial one.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include "garminusb.h"
 #include "gpsusbint.h"
 
-int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet)
+/*
+ * Return values are:
+ * Negative on error.
+ * 1 if read success - even if empty packet.
+ */
+int32 GPS_Packet_Read_usb(gpsdevh *dh, GPS_PPacket *packet, int eat_bulk)
 {
        int32  n;
-       int32  i;
        int32 payload_size;
-       const char *m1;
-       const char *m2;
 
        garmin_usb_packet pkt;
+
        memset(&pkt, 0, sizeof(pkt));
+do_over:
        n = gusb_cmd_get(&pkt, sizeof(pkt));
 
-       if ( n <= 0 ) {
-// FIXME: revisit why we're intermittend getting read errors here...
-// fprintf(stderr, "Eeek %d\n", n);
-               (*packet)->n = (UC) 0;
+       if ( n < 0 ) {
+fprintf(stderr, "Eeek %d\n", n);
                return n;
        }
 
-       if (1 && gps_show_bytes) {
-               GPS_Diag("\nRx Data:[%d]",n);
-               for (i = 0; i < n; i++)
-                   GPS_Diag("%02x ", pkt.dbuf[i]);
-               for (i = 0; i < n; i++)
-                   GPS_Diag("%c", isalnum(pkt.dbuf[i]) ? pkt.dbuf[i] : '.');
-               m1 = Get_Pkt_Type(pkt.gusb_pkt.pkt_id[0], pkt.gusb_pkt.databuf[0], &m2);
-               GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
-
+       /*
+        * This is a horrible hack for 276/296.   This family sometimes 
+        * switches between bulk and interrupt on EVERY packet.   Rather 
+        * than bother all the callers with that bit of unpleasantness, 
+        * silently consume zero byte "switch back to intr"  packets here.
+        *
+        * The one caller that doesn't want this hidden is device discovery
+        * in the A000 handler.
+        */
+       if ((n == 0) && eat_bulk)  {
+               goto do_over;
        }
-
+       
        /* 
         * Populate members of serial packet from USB packet.   The
         * copy here seems wasteful, but teaching all the callers about
@@ -64,5 +68,6 @@ int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet)
        payload_size = le_read32(&pkt.gusb_pkt.datasz);
        (*packet)->n = (UC) payload_size;
        memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size);
-       return payload_size;
+       
+       return 1;
 }
index 798b5af3d5af5fe2a434fa7b7839665b4feefdbc..bd376b7e0f2fd09497e2f142f2c548e8c76ff56e 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Form GarminUSB packets to send.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -43,7 +43,7 @@ GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n)
 }
 
 int32
-GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet)
+GPS_Write_Packet_usb(gpsdevh *dh, GPS_PPacket packet)
 {
        garmin_usb_packet gp;
        memset(&gp, 0, sizeof(gp));
index 2209783f548c029533123169e84cf969382f08d0..d5ee15be85bd75c09b9b554c49c67a17bc186113 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Stubs to keep build happy when USB just isn't available to us.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -20,9 +20,9 @@
  */
 
 
-#include "garminusb.h"
 #include "config.h"
-#if !HAVE_LIBUSB
+#if !HAVE_LIBUSB 
+#include "garminusb.h"
 
 const char no_usb[] = "USB suport is not available in this build.\n";
 int
index a503c9cf2bee09680392bfe3dcfdfe625400c82c..cd217cb67647d5188b428e49c09c612e860ce634 100644 (file)
@@ -2,7 +2,7 @@
 /*
     Windows layer of Garmin/USB protocol.
 
-    Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+    Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -31,6 +31,8 @@
 #include "gps.h"
 #include "gpsapp.h"
 #include "garminusb.h"
+#include "gpsusbcommon.h"
+#include "gpsusbwin.h"
 
 /* Constants from Garmin doc. */
 
@@ -49,140 +51,25 @@ DEFINE_GUID(GARMIN_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0x
        (FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
 
-static HANDLE *usb_handle ;
+static HANDLE *usb_handle = INVALID_HANDLE_VALUE;
 static int usb_tx_packet_size ;
 
-static const char  oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0};
-garmin_usb_packet iresp;
-garmin_usb_packet iresp_junk;
-static int ct;
-
-static char * id_unit(void);
-
-int
-gusb_open(const char *pname)
-{
-       int maxtries;
-       int maxct = 10;
-       int unit_number = 0;
-       int req_unit_number = 0;
-
-       SP_INTERFACE_DEVICE_DATA devinterface;
-       PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
-       SP_DEVINFO_DATA devinfo;
-       HDEVINFO hdevinfo;
-       DWORD size;
-       if (ct++) return 1;
-
-       if (strlen(pname) > 4) {
-               req_unit_number = atoi(pname+4);
-               GPS_Diag("Searching for USB unit number %d\n", unit_number);
-// if (req_unit_number == -2) {
-// printf("%d %u %s\n", 0, 3019840053, "GPSMap60CS Software Version 3.50");
-// exit(0);
-// }
-       }
-
-       hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL, 
-                       DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
-
-       if (hdevinfo == INVALID_HANDLE_VALUE) {
-               GPS_Serial_Error("SetupDiGetClassDevs failed");
-               warning("Is the Garmin USB driver installed?");
-               return 0;
-       }
-
-       /* Get the device associated with this index. */
-       devinterface.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
-       if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, (GUID *) &GARMIN_GUID, 
-                       0, &devinterface)) {
-               GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
-               warning("Is the Garmin USB unit powered up and connected?");
-               return 0;
-       }
-
-       SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, 
-                       NULL, 0, &size, NULL);
-
-       pdd = malloc(size);
-       pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
-       devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
-
-       if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, pdd, size, NULL, &devinfo)) {
-               GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail");
-               return 0;
-       }
-
-       /* Whew.  All that just to get something we can open... */
-       GPS_Diag("Windows GUID for interface %d is \n\t%s\n", unit_number, 
-                       pdd->DevicePath);
-       usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE, 
-                       0, NULL, OPEN_EXISTING, 0, NULL );
-       if (usb_handle == INVALID_HANDLE_VALUE) {
-               GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath);
-               return 0;
-       }
-
-       if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, NULL, 0,
-                       &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, &size, NULL)) {
-               fatal("Couldn't get USB packet size.\n");
-       }
-
-       if (pdd) {
-               free(pdd);
-       }
-       SetupDiDestroyDeviceInfoList(hdevinfo);
-
-       for (maxtries = maxct; maxtries; maxtries--) {
-
-               le_write16(&iresp.gusb_pkt.pkt_id, 0);
-               le_write32(&iresp.gusb_pkt.datasz, 0);
-               le_write32(&iresp.gusb_pkt.databuf, 0);
-
-               gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
-               gusb_cmd_get(&iresp, sizeof(iresp));
-
-               if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) && 
-                       (le_read32(iresp.gusb_pkt.datasz) == 4)) {
-                       unsigned serial_number = le_read32(iresp.gusb_pkt.databuf);
-                       GPS_Diag("Serial %u. Synced in %d\n", 
-                                       serial_number,
-                                       maxct - maxtries);
-                       garmin_unit_info[unit_number].serial_number = serial_number;
-                       garmin_unit_info[unit_number].os_identifier = strdup(pdd->DevicePath);
-                       garmin_unit_info[unit_number].product_identifier = id_unit();
-                       if (req_unit_number < 0) {
-                               printf("%d %u %s\n", unit_number, serial_number, garmin_unit_info[unit_number].product_identifier);
-                               return 2;
-                       }
-                       return 1;
-               }
-       }
-       fatal("Unable to establish USB syncup within %d tries.\n", maxct);
-       return 0;
-}
-
 int 
-gusb_close(const char *portname)
+gusb_win_close(const char *portname)
 {
        if (usb_handle != INVALID_HANDLE_VALUE) {
-#if 0
-               /* FIXME: we should probably release things and delete the "ct" 
-                * reference count above... 
-                */
                CloseHandle(usb_handle);
                usb_handle = INVALID_HANDLE_VALUE;
-#endif
        }
-  return 0;
+
+       return 0;
 }
 
-int
-gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
+static int
+gusb_win_get(garmin_usb_packet *ibuf, size_t sz)
 {
        DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE;
        unsigned char *buf = (unsigned char *) &ibuf->dbuf;
-       int i;
        int tsz=0;
        unsigned char *obuf = buf;
 
@@ -202,44 +89,32 @@ gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
                        break;
                }
        }
-
-       if (gps_show_bytes) {
-               const char *m1, *m2;
-               printf("RX [%d]:", tsz);
-               for(i=0;i<tsz;i++)
-                       GPS_Diag("%02x ", obuf[i]);
-               for(i=0;i<tsz;i++)
-                       GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
-               
-               m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2);
-               GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
-               printf("\n");
-       }
        return tsz;
 }
 
-int
-gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
+static int
+gusb_win_get_bulk(garmin_usb_packet *ibuf, size_t sz)
+{
+       int n;
+       DWORD rsz;
+       unsigned char *buf = (unsigned char *) &ibuf->dbuf;
+
+       n = ReadFile(usb_handle, buf, sz, &rsz, NULL);
+
+       return rsz;
+}
+
+static int
+gusb_win_send(const garmin_usb_packet *opkt, size_t sz)
 {
        DWORD rsz;
-       size_t i;
        unsigned char *obuf = (unsigned char *) &opkt->dbuf;
-       const char *m1, *m2;
 
        /* The spec warns us about making writes an exact multiple
         * of the packet size, but isn't clear whether we can issue
         * data in a single call to WriteFile if it spans buffers.
         */
        WriteFile(usb_handle, obuf, sz, &rsz, NULL);
-       if (gps_show_bytes) {
-               printf("TX [%d]:", rsz);
-               for(i=0;i<rsz;i++)
-                       GPS_Diag("%02x ", obuf[i]);
-               for(i=0;i<rsz;i++)
-                       GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
-               m1 = Get_Pkt_Type(opkt->gusb_pkt.pkt_id[0], opkt->gusb_pkt.databuf[0], &m2);
-               GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
-       }
 
        if (rsz != sz) {
                fatal ("Error sending %d bytes.   Successfully sent %d\n", sz, rsz);
@@ -254,47 +129,127 @@ gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
        return rsz;
 }
 
-static char *
-id_unit(void)
+static gusb_llops_t win_llops = {
+       gusb_win_get,
+       gusb_win_get_bulk,
+       gusb_win_send,
+       gusb_win_close
+};
+
+static
+HANDLE * garmin_usb_start(HDEVINFO* hdevinfo, SP_DEVICE_INTERFACE_DATA *infodata)
 {
-static const unsigned char  oid[12] = {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
-       /* 
-        * Identify the unit before getting into all the protocol gunk.
-        * We get two packets back, but we discard the protocol array 
-        * for now.
-        */
+       DWORD size;
+       PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
+       SP_DEVINFO_DATA devinfo;
+
+       SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata, 
+                       NULL, 0, &size, NULL);
+
+       pdd = xmalloc(size);
+       pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
+
+       devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
+       if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata, 
+               pdd, size, NULL, &devinfo)) {
+                       GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail");
+                       return NULL;
+       }
 
-       gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid));
-       gusb_cmd_get(&iresp, sizeof(iresp));
-       gusb_cmd_get(&iresp_junk, sizeof(iresp_junk));
+       /* Whew.  All that just to get something we can open... */
+       GPS_Diag("Windows GUID for interface is \n\t%s\n", 
+                       pdd->DevicePath);
 
-       if (iresp.gusb_pkt.type == 20 && 
-               le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
-               return strdup(iresp.gusb_pkt.databuf+4);
+       if (usb_handle != INVALID_HANDLE_VALUE) {
+               fatal("garmin_usb_start called while device already started.\n");
        }
 
-       return NULL;
-}
+       usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE, 
+                       0, NULL, OPEN_EXISTING, 0, NULL );
+       if (usb_handle == INVALID_HANDLE_VALUE) {
+               GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath);
+               return NULL;
+       }
+
+       if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, 
+           NULL, 0, &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, 
+           &size, NULL)) {
+                fatal("Couldn't get USB packet size.\n");
+        }
+
+       gusb_syncup();
 
+       return usb_handle;
+}
 
-#if 0
-main()
+/*
+ * Main entry point from the upper layer.   Walk the device tree, find our
+ * device, and light it up.
+ */
+int
+gusb_init(const char *pname, gpsdevh **dh)
 {
-       DWORD sz;
-char ocmd[] = {00, 00, 00, 00, 05, 00, 00, 00, 00, 00, 00, 00};
-char ocmd2[] = {0x14, 00, 00, 00, 0xfe, 00, 00, 00, 00, 00, 00, 00};
-       gusb_open();
-       WriteFile(usb_handle, ocmd, sizeof(ocmd), &sz, NULL);
-       printf("Wrote %d\n", sz);
-       usb_intr_get();
-
-       WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL);
-       printf("Wrote %d\n", sz);
-       usb_intr_get();
-
-       WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL);
-       printf("Wrote %d\n", sz);
-       usb_intr_get();
+       int req_unit_number = 0;
+       int un = 0;
+       int match;
+
+       HDEVINFO hdevinfo;
+       SP_DEVICE_INTERFACE_DATA devinterface;
+
+       winusb_unit_data *wud = xcalloc(sizeof (winusb_unit_data), 1);
+       *dh = (gpsdevh*) wud;
+
+       gusb_register_ll(&win_llops);
+
+       if (strlen(pname) > 4) {
+               req_unit_number = atoi(pname+4);
+       }
+
+       hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL, 
+                       DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+
+       if (hdevinfo == INVALID_HANDLE_VALUE) {
+               GPS_Serial_Error("SetupDiGetClassDevs failed");
+               warning("Is the Garmin USB driver installed?");
+               return 0;
+       }
+
+       devinterface.cbSize = sizeof(devinterface);
+       
+       if (req_unit_number >= 0) {
+               if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, 
+                               (GUID *) &GARMIN_GUID, 
+                               req_unit_number, &devinterface)) {
+                       GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
+                       warning("Is the Garmin USB unit number %d powered up and connected?", un);
+                       return 0;
+               }
+               /* We've matched.  Now start the specific unit. */
+               garmin_usb_start(hdevinfo, &devinterface);
+               return 1;
+       }
+
+       /* 
+        * Out unit nunber  is less than zero, so loop over all units
+        * and display them.
+        */
+       for(match = 0;;match++) {
+               if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, 
+                       (GUID *) &GARMIN_GUID, match, &devinterface)) {
+                       if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+                               break;
+                       } else {
+                               GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
+                               warning("Is the Garmin USB unit number %d powered up and connected?", un);
+                               return 0;
+                       }       
+               }
+               /* We've matched.  Now start the specific unit. */
+               garmin_usb_start(hdevinfo, &devinterface);
+               gusb_close("blah");
+       }
+       gusb_list_units();
+       exit (0);
 }
-#endif
+
 #endif /* !defined(NO_USB) */
index e22a8ba60342ac4a795643d1602e3b2b9d67adbc..faf1e0f06a25e25d92234f88368929a9c4009a2a 100644 (file)
@@ -26,6 +26,7 @@ uint32 GPS_Util_Get_Uint(const UC *s);
 
 void   GPS_Warning(char *s);
 void   GPS_Error(char *fmt, ...);
+void   GPS_Serial_Error(const char *hdr, ...);
 void   GPS_Fatal(char *s);
 void   GPS_Enable_Error(void);
 void   GPS_Enable_Warning(void);